我需要多次调用worker方法才能将数据加载到数据库中。我想对此进行一些并行处理,并能够指定要使用的线程数。我曾想过使用mod运算符来拆分工作负载,但是却陷入了如何使用async
await
来实现的想法。
因此,异步方法必须创建n
个线程,然后调用worker方法,以使n
个工作流并行发生。 worker方法是同步的。
我尝试了一下,但是很确定如何实现我想要的。有这种模式吗?
我正在玩的一些代码:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TestingAsync
{
class Program
{
static void Main(string[] args)
{
int threads = 3;
int numItems = 10;
Task task = ThreadIt(threads, numItems);
}
static async Task ThreadIt(int threads, int numItems)
{
Console.WriteLine($"Item limit: {numItems}, threads: {threads}");
for (int i = 0; i < numItems; i++)
{
Console.Write($"Adding item: {i} mod 1: {i % threads}. ");
int task = await DoSomeWork(i%threads, 500);
}
}
static async Task<int> DoSomeWork(int Item, int time)
{
Console.Write($" Working.on item {Item}..");
Thread.Sleep(time );
Console.WriteLine($"done.");
return Item;
}
}
}
编辑:
我要重新表述,因为可能我的需求不清楚。
我想要创建n
个线程。将有x
个项目要处理,我希望使用mod
(或其他方式)将它们排队,然后在n
线程中按顺序并行处理。完成一项后,我希望立即处理下一项,而不要等待所有三个线程完成。 某些项目要比其他项目花费更长的时间,甚至可能要多花10倍的时间,因此其他线程不应等待其中一个线程完成。
例如,如果我们有3个线程和9个项目,则会发生这种情况:
thread1: items 0,3,6
thread2: items 1,4,7
thread3: items 2,5,8
每个线程按顺序处理其工作负载,并且不会在每个项目之间等待。
答案 0 :(得分:2)
您可以尝试创建List<Task<T>>
并启动它们,然后如果要完成所有任务,则可以使用await
来WhenAll
,如果要完成所有任务,则可以WhenAny
:
static async Task ThreadIt(int threads, int numItems)
{
List<Task<int>> tasks = new List<Task<int>>();
Console.WriteLine($"Item limit: {numItems}, threads: {threads}");
for (int i = 0; i < numItems; i++)
{
Console.Write($"Adding item: {i} mod 1: {i % threads}. ");
tasks.Add(DoSomeWork(i%threads, 500));
}
var result = await Task.WhenAll(tasks);
}
,当使用Task
,async
和await
时,我们应该使用Task.Delay
而不是Thread.Sleep
:
static async Task<int> DoSomeWork(int Item, int time)
{
Console.Write($" Working.on item {Item}..");
await Task.Delay(time); // note this
Console.WriteLine($"done.");
return Item;
}
编辑:
您可以创建一个ConcurrentQueue
,然后在3个任务完成时每次出队,并生成下3个任务,例如:
static async Task ThreadIt(int threads, int numItems)
{
ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
Enumerable.Range(0, 10).ForEach(x => queue.Enqueue(x));
List<Task<int>> tasks = new List<Task<int>>();
Console.WriteLine($"Item limit: {numItems}, threads: {threads}");
while (!queue.IsEmpty)
{
for (int i = 0; i < threads; i++)
{
if(queue.TryDequeue(out int val))
{
Console.Write($"Adding item: {val} mod 1: {val % threads}. ");
tasks.Add(DoSomeWork(val%threads, 500));
}
}
var result = await Task.WhenAll(tasks);
}
}
答案 1 :(得分:1)
我需要多次调用worker方法才能将数据加载到数据库中。我想对此进行一些并行处理,并能够指定要使用的线程数... worker方法是同步的...是否有这种模式?
是的,任务并行库。
给出:
static int DoSomeWork(int Item, int time)
{
Console.Write($" Working.on item {Item}..");
Thread.Sleep(time);
Console.WriteLine($"done.");
return Item;
}
您可以将其并行化:
static List<int> ThreadIt(int threads, int numItems)
{
Console.WriteLine($"Item limit: {numItems}, threads: {threads}");
var items = Enumerable.Range(0, numItems);
return items.AsParallel().WithDegreeOfParallelism(threads)
.Select(i => DoSomeWork(i, 500))
.ToList();
}