如何在C#中异步生成多个线程以多次调用方法?

时间:2019-01-08 08:37:48

标签: c# asynchronous

我需要多次调用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

每个线程按顺序处理其工作负载,并且不会在每个项目之间等待。

2 个答案:

答案 0 :(得分:2)

您可以尝试创建List<Task<T>>并启动它们,然后如果要完成所有任务,则可以使用awaitWhenAll,如果要完成所有任务,则可以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);
}

,当使用Taskasyncawait时,我们应该使用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();
}