我有这段代码(简化的)可以在100个不同的并行线程上处理参数数组,但是变量x和y在线程中使用时会被线程内的循环更改。如果我使用1个线程运行该函数,那么它将起作用。
我还尝试将参数放入ConcurrentBag中,并使用foreach进行循环,但结果相同,线程中混合了参数。
List<Task> tasks = new List<Task>();
var listConcurentBag = new ConcurrentBag<int>();
int nThreadCount = 0;
for (x=0; x<1000; x++)
for (y=0; y<1000; y++)
{
int x1=x;
int y2=y;
Task t = Task.Run(() =>
{
int param1=x1;
int param2=y2;
// some calculations with param1 and param2
listConcurentBag.Add(result);
}); // tasks
tasks.Add(t);
nThreadCount++;
if (nThreadCount == 100) // after 100 threads started, wait
{
nThreadCount = 0;
Task.WaitAll(tasks.ToArray());
tasks.Clear();
}
}
答案 0 :(得分:2)
您应该使用Microsoft的Reactive Framework(又名Rx)-NuGet System.Reactive
并添加using System.Reactive.Linq;
-然后您可以执行以下操作:
var query =
from x in Observable.Range(0, 1000)
from y in Observable.Range(0, 1000)
from r in Observable.Start(() => GetResult(x, y))
select new { x, y, r };
IDisposable subscription =
query
.Buffer(100)
.Subscribe(results =>
{
/* do something with each buffered list of results */
});
现在,这与您当前的代码并不完全相同,但是使用线程池的最大容量后,它会立即为您提供100个结果块。
您可以更改它以设置并发性:
var query =
from x in Observable.Range(0, 1000)
from y in Observable.Range(0, 1000)
select Observable.Start(() => new { x, y, r = GetResult(x, y) });
IDisposable subscription =
query
.Merge(maxConcurrent: 100) // limit to 100 threads
.Buffer(count: 100) // produce 100 results at a time
.Subscribe(results =>
{
/* do something with the list of results */
});
如果您想在代码自然完成之前停止代码,只需调用subscription.Dispose();
。
Rx确实会产生更清晰的代码,恕我直言。
答案 1 :(得分:1)
我有一个替代实施的建议,您可能会发现也可能不适合您的需求。而不是分批处理任务
您可以将nested-for循环表示为单个可枚举,然后将其提供给内置方法Parallel.ForEach
进行并行处理。
private IEnumerable<(int, int)> GetNestedFor()
{
for (int x = 0; x < 1000; x++)
{
for (int y = 0; y < 1000; y++)
{
yield return (x, y); // return a ValueTuple<int, int>
}
}
}
ThreadPool.SetMinThreads(100, 100);
var options = new ParallelOptions() { MaxDegreeOfParallelism = 100 };
Parallel.ForEach(GetNestedFor(), options, item =>
{
int param1 = item.Item1;
int param2 = item.Item2;
Console.WriteLine($"Processing ({param1}, {param2})");
Thread.Sleep(100); // Simulate some work
});
输出:
处理(0,1)
处理中(0,2)
处理中(0,0)
处理中(0,3)
...
处理中(0,998)
处理中(0,997)
处理中(0,999)
处理中(1,0)
处理中(1,1)
...
处理中(999,999)
处理中(999,998)