.net 你在使用并行扩展吗?

.net 你在使用并行扩展吗?,.net,parallel-processing,task,task-parallel-library,plinq,.net,Parallel Processing,Task,Task Parallel Library,Plinq,我希望这不是对stackoverflow的滥用;最近我在这里看到了一些关于并行扩展的好问题,这引起了我的兴趣 我的问题: 您是否正在使用并行扩展,如果是,如何使用 我叫Stephen Toub,是微软并行计算平台团队的成员。我们是负责并行扩展的小组。我总是很感兴趣地听到开发人员如何利用并行扩展(例如Parallel.For、PLINQ、concurrentdirectionary等)、您的积极体验、消极体验、对未来的功能要求等等。 如果您愿意分享这些信息,请在这里作为对这个问题的回答,或者通过电

我希望这不是对stackoverflow的滥用;最近我在这里看到了一些关于并行扩展的好问题,这引起了我的兴趣

我的问题: 您是否正在使用并行扩展,如果是,如何使用

我叫Stephen Toub,是微软并行计算平台团队的成员。我们是负责并行扩展的小组。我总是很感兴趣地听到开发人员如何利用并行扩展(例如Parallel.For、PLINQ、concurrentdirectionary等)、您的积极体验、消极体验、对未来的功能要求等等。
如果您愿意分享这些信息,请在这里作为对这个问题的回答,或者通过电子邮件(microsoft.com的
stoub
)私下告诉我

我非常期待你的来信


提前谢谢

我一直在我的项目中使用它。我有一个基于MSBuild的DSL编译管道,单阶段类型是多对多阶段。M:M阶段使用.AsParallel.ForAll(…)

以下是:

受保护的密封覆盖IEnumerable进程()
{
if(this.Input.Count()>1)
{
这个。输入
.天冬酰胺()
.ForAll(这个过程);
}
else if(this.Input.Any())
{
this.Process(this.Input.Single());
}
返回此.Input.ToArray();
}

我正在使用TPL进行嵌套的
并行.ForEach
调用。因为我从这些调用中访问字典,所以我必须使用
concurrentdirectionary
。虽然很好,但我有几个问题:

  • ForEach
    中的代理没有做很多工作,因此我没有获得多少并行性。系统似乎花费了大部分时间连接线程。如果有一种方法可以找出为什么并发性没有得到改善并加以改进,那就太好了

  • 内部
    ForEach
    迭代超过了
    ConcurrentDictionary
    实例,如果我没有添加枚举器缓存,这将导致系统花费大量时间为字典使用枚举器

  • 我的许多
    ConcurrentDictionary
    实例实际上都是集合,但是没有
    ConcurrentSet
    ,因此我必须用
    ConcurrentDictionary
    实现自己的实例

  • ConcurrentDictionary
    不支持对象初始化语法,所以我不能说
    var dict=newConcurrentDictionary{{'A',65}
    这也意味着我不能将
    ConcurrentDictionary
    文本分配给类成员

  • 在某些地方,我必须在
    ConcurrentDictionary
    中查找一个键,并调用一个昂贵的函数来创建一个不存在的值。如果有一个重载
    GetOrAdd
    ,它接受一个
    addValueFactory
    ,这样只有在键不存在时才能计算值,那就更好了。这可以用
    .AddOrUpdate(key,addValueFactory,(k,v)=>v)
    来模拟,但这会增加每次查找的额外委托调用的开销


我还没有广泛地使用它,但我肯定一直在关注它的使用情况,并在我们的代码库中寻找机会来使用它(不幸的是,我们的许多项目目前仍在使用.NET-2.0)。我自己想出的一个小宝贝是一个独特的单词计数器。我认为这是我能想到的最快、最简洁的实现——如果有人能把它做得更好,那将是了不起的:

private static readonly char[] delimiters = { ' ', '.', ',', ';', '\'', '-', ':', '!', '?', '(', ')', '<', '>', '=', '*', '/', '[', ']', '{', '}', '\\', '"', '\r', '\n' };
private static readonly Func<string, string> theWord = Word;
private static readonly Func<IGrouping<string, string>, KeyValuePair<string, int>> theNewWordCount = NewWordCount;
private static readonly Func<KeyValuePair<string, int>, int> theCount = Count;

private static void Main(string[] args)
{
    foreach (var wordCount in File.ReadAllText(args.Length > 0 ? args[0] : @"C:\DEV\CountUniqueWords\CountUniqueWords\Program.cs")
        .Split(delimiters, StringSplitOptions.RemoveEmptyEntries)
        .AsParallel()
        .GroupBy(theWord, StringComparer.OrdinalIgnoreCase)
        .Select(theNewWordCount)
        .OrderByDescending(theCount))
    {
        Console.WriteLine(
            "Word: \""
            + wordCount.Key
            + "\" Count: "
            + wordCount.Value);
    }

    Console.ReadLine();
}

private static string Word(string word)
{
    return word;
}

private static KeyValuePair<string, int> NewWordCount(IGrouping<string, string> wordCount)
{
    return new KeyValuePair<string, int>(
        wordCount.Key,
        wordCount.Count());
}

private static int Count(KeyValuePair<string, int> wordCount)
{
    return wordCount.Value;
}
private static readonly char[]分隔符={'、'.'、'.'、';'、'\''.-'、':'、'!'、'?'、'('、')、''''='、'*'、'/'、'['、'.']、'{'、'}'、'\\'、''.'、'\r'、'\n'};
私有静态只读Func theWord=Word;
私有静态只读函数theNewWordCount=NewWordCount;
私有静态只读Func theCount=Count;
私有静态void Main(字符串[]args)
{
foreach(文件.ReadAllText中的var wordCount(args.Length>0?args[0]:@“C:\DEV\CountUniqueWords\CountUniqueWords\Program.cs”)
.Split(分隔符、StringSplitOptions.RemoveEmptyEntries)
.天冬酰胺()
.GroupBy(单词、StringComparer.OrdinalIgnoreCase)
。选择(新建或计数)
.OrderByDescending(计数))
{
控制台写入线(
“单词:\”
+wordCount.Key
+“\”计数:
+wordCount.Value);
}
Console.ReadLine();
}
专用静态字符串字(字符串字)
{
返回词;
}
私有静态KeyValuePair NewWordCount(iGroup wordCount)
{
返回新的KeyValuePair(
wordCount.Key,
Count.Count());
}
私有静态整数计数(KeyValuePair字计数)
{
返回wordCount.Value;
}
我们没有广泛使用它,但它确实派上了用场

通过在
Parallel.Invoke()
调用中包装一些更耗时的步骤,我能够将一些运行时间较长的单元测试的运行时间减少到原来的1/3左右

我也喜欢使用并行库来测试线程安全性。我发现并报告了Ninject的几个线程问题,代码如下:

var repositoryTypes = from a in CoreAssemblies
                    from t in a.GetTypes()
                    where t.Name.EndsWith("Repository")
                    select t;
repositoryTypes.ToList().AsParallel().ForAll(
    repositoryType => _kernel.Get(repositoryType));

在我们实际的生产代码中,我们使用一些并行扩展来运行一些集成操作,这些操作应该每隔几分钟运行一次,主要包括从web服务中提取数据。由于web连接固有的高延迟,这特别利用了并行性,并允许我们的所有作业在运行之前完成它们应该会再次启动。

我使用的ConcurrentDictionary存储了1亿多个项目。我的应用程序当时使用了大约8 GB的内存。ConcurrentDictionary随后决定它要在另一个Add上增长。它显然要增长很多(一些内部prima算法)因为内存不足。这是在x64上,内存为32GB

所以我想要一个bo
var repositoryTypes = from a in CoreAssemblies
                    from t in a.GetTypes()
                    where t.Name.EndsWith("Repository")
                    select t;
repositoryTypes.ToList().AsParallel().ForAll(
    repositoryType => _kernel.Get(repositoryType));