如何在 C# 中并行和顺序运行方法?

Dev*_*Dev 0 c# task-parallel-library

我有一个 C# 控制台应用程序。在这个应用程序中,我有一个方法可以调用DoWorkAsync。对于此问题的上下文,此方法如下所示:

private async Task<string> DoWorkAsync()
{
  System.Threading.Thread.Sleep(5000);

  var random = new Random();

  var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  var length = random.Next(10, 101);

  await Task.CompletedTask;
  return new string(Enumerable.Repeat(chars, length)
      .Select(s => s[random.Next(s.Length)]).ToArray());
}
Run Code Online (Sandbox Code Playgroud)

DoWorkAsync从另一种方法调用,该方法确定 a) 这将运行多少次,以及 b) 每个调用是并行还是按顺序运行。该方法如下所示:

private async Task<Task<string>[]> DoWork(int iterations, bool runInParallel)
{
  var tasks = new List<Task<string>>();
  for (var i=0; i<iterations; i++)
  {
    if (runInParallel)
    {
      var task = Task.Run(() => DoWorkAsync());
      tasks.Add(task);
    }
    else
    {
      await DoWorkAsync();
    }
  }

  return tasks.ToArray();
}
Run Code Online (Sandbox Code Playgroud)

完成所有任务后,我想显示结果。为此,我的代码如下所示:

var random = new Random();
var tasks = await DoWork(random.Next(10, 101);
Task.WaitAll(tasks);

foreach (var task in tasks)
{
  Console.WriteLine(task.Result);
}
Run Code Online (Sandbox Code Playgroud)

如果代码并行运行(即runInParalleltrue),则此代码按预期工作。但是,当runInParallel为 false(即我想按顺序运行任务)时,Task不会填充数组。所以,调用者没有任何结果可以处理。我不知道如何修复它。我不确定如何将方法调用添加为Task将按顺序运行的a 。我知道 Tasks 背后的想法是并行运行。但是,我需要在并行和顺序之间切换。

谢谢!

Gur*_*ron 5

Task阵列没有得到填充。

所以填充它:

else
{
  var task = DoWorkAsync();
  tasks.Add(task);
  await task;
}
Run Code Online (Sandbox Code Playgroud)

聚苯乙烯

此外,您DoWorkAsync对我来说看起来有点不对劲,为什么Thread.Sleep和不是await Task.Delay(这是模拟异步执行的更正确的方法,您也不需要await Task.CompletedTask这种方式)。如果您希望 DoWorkAsync受 CPU 限制,只需将其设置为:

private Task<string> DoWorkAsync()
{
    return Task.Run(() =>
    {
        // your cpu bound work
        return "string";
    });
}
Run Code Online (Sandbox Code Playgroud)

之后,您可以执行以下操作(对于异步/CPU 绑定工作):

private async Task<string[]> DoWork(int iterations, bool runInParallel)
{
    if(runInParallel)
    {
        var tasks = Enumerable.Range(0, iterations)
            .Select(i => DoWorkAsync());
        return await Task.WhenAll(tasks);
    }
    else
    {
        var result = new string[iterations];
        for (var i = 0; i < iterations; i++)
        {
            result[i] = await DoWorkAsync();
        }
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)