C# 实现并发操作的最佳方法
我有两个包含不同长度字符串的列表。我需要使用一个算法(比如AlgorithmX)来比较这两个列表,该算法将确定是否应该保留ListA中的字符串。列表很长(每个列表超过50000个项目),长度从1个字符到5000个字符不等 因此,我们至少要进行50000*50000次比较(不是直接比较,列表中的每个字符串都要经过AlgorthmX) 现在我对多线程的知识还不多。但我一直在阅读它。然而在.Net中有各种各样的实现。标准线程、任务、等待异步 使用AlgorithmX和多线程进行列表比较的最佳方法是什么?也就是说,我应该使用await async任务库吗 我是否应该在每个CPU上平均分割ListA的项目,并针对ListB运行算法?我是否应该在分割列表上使用concurrentQueue [编辑] ConcurrentQueue似乎是我要找的……但欢迎添加任何内容C# 实现并发操作的最佳方法,c#,multithreading,asynchronous,async-await,task-parallel-library,C#,Multithreading,Asynchronous,Async Await,Task Parallel Library,我有两个包含不同长度字符串的列表。我需要使用一个算法(比如AlgorithmX)来比较这两个列表,该算法将确定是否应该保留ListA中的字符串。列表很长(每个列表超过50000个项目),长度从1个字符到5000个字符不等 因此,我们至少要进行50000*50000次比较(不是直接比较,列表中的每个字符串都要经过AlgorthmX) 现在我对多线程的知识还不多。但我一直在阅读它。然而在.Net中有各种各样的实现。标准线程、任务、等待异步 使用AlgorithmX和多线程进行列表比较的最佳方法是什么
欢迎使用任何指针!这是一种可能的实现,它使用
ConcurrentQueue
存储算法决定保留的字符串(注意:没有特别的理由不使用其他线程安全集合)
此方法用于迭代列表a
:
private static void Main()
{
var listA = new[] {"the", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog"};
var listB = new List<string>(new[] {"fox", "dog", "cat", "mouse"});
var stringsToKeep = new ConcurrentQueue<string>();
Parallel.ForEach(listA, a =>
{
var shouldKeep = AlgorithmX(a, listB);
if (shouldKeep)
{
stringsToKeep.Enqueue(a);
}
});
Console.WriteLine($"Matching strings: {string.Join(", ", stringsToKeep.ToArray())}");
}
private static void Main()
{
var listA=new[]{“the”,“quick”,“brown”,“fox”,“jumped”,“over”,“the”,“lazy”,“dog”};
var listB=新列表(新[]{“狐狸”、“狗”、“猫”、“老鼠”});
var stringstokep=新的ConcurrentQueue();
Parallel.ForEach(listA,a=>
{
var shouldKeep=AlgorithmX(a,listB);
如果(应该保持)
{
列队(a);
}
});
WriteLine($”匹配字符串:{string.Join(“,”,stringsToKeep.ToArray())});
}
假设:
ListA
或ListB
。只要不修改它们,就不会出现并发访问问题(在多线程环境中,对列表的只读访问是可以的-只有当列表被修改时才会出现并发问题-例如插入/删除/等等)
AlgorithmX
没有副作用(即,该方法是“纯”的,因此线程安全的-能够在没有问题的情况下并发调用)ListA
中的字符串顺序不需要反映在结果中(即,您不关心算法决定保留的字符串顺序)async
/await
在这里不合适。“并发性”一次做不止一件事。异步是一种不使用专用线程进行操作的并发形式,您可以将其视为更基于事件的并发形式。并行是一种使用多个线程进行操作的并发形式。异步和并行都是并发形式,但在出现时是相反的因此,异步通常用于I/O绑定或其他与CPU无关的任务,如计时器;并行通常用于CPU工作,如运行一百万次计算算法
关于并行性,通常来说,最好使用具有最高抽象的工具。手动线程是正确的,就像直接使用线程池一样
在您的例子中,您希望使用Parallel
或Parallel LINQ,两者都构建在任务并行库之上,而任务并行库又使用线程池
有一个问题,但我发现,如果您需要一个操作的结果,并行LINQ通常会产生更简单的代码。在这种情况下:
static List<string> RunAlgorithm(List<string> listA, List<string> listB)
{
return listA.AsParallel()
.Where(a => AlgorithmX(a, listB)).ToList();
}
AlgorithmX只是一个交集还是更复杂的东西?所以你既不修改ListA也不修改ListB?你想使用ConcurrentQueue来存储要保留的字符串的结果?这也是我的第一种方法。分区可能有意义。很难说。最后它需要试验真实数据和真实算法,
static List<string> RunAlgorithm(List<string> listA, List<string> listB)
{
return listA.AsParallel().AsOrdered()
.Where(a => AlgorithmX(a, listB)).ToList();
}