如何在循环中异步执行 运行 任务?

How do I asynchronously run tasks in a loop?

我有一个 .NET 3.1 Core 应用程序。我正在学习使用任务并行库。为此,我想创建一个基本的 Task。我想通过扩展方法 运行 这个 Task 。此时,我有以下内容:

var tasks = new List<Task<int>>();       // Used to track the calculated result
var details = new List<Details>();       // Used for debugging purposes

var random = new Random();               // Used to generate a random wait time
var offset = 10;                         // This value is used to perform a basic calculation

// The following tasks should run the tasks OUT OF ORDER (i.e. 4, 5, 2, 3, 1)
var stopwatch = Stopwatch.StartNew();    // Keep track of how long all five calculations take
for (var i=1; i<=5; i++)
{
  var shouldBe = i + offset;
  var d = new Details();

  var t = new Task<int>(() => {
    var ms = random.Next(1001);    // Choose a wait time between 0 and 1 seconds
    Thread.Sleep(ms);
    d.SleepTime = ms;

    var result = i + offset;
    Console.WriteLine($"{i} + {offset} = {result}  (over {timeout} ms.)");
    return result;
  });

  tasks.Add(t.ExecuteAsync<int>());
  details.Add(d);
}
stopwatch.Stop();

Task.WaitAll(tasks.ToArray());
foreach (var t in tasks)
{
  Console.WriteLine($"Result: {t.Result}");
}

// Calculate how long the whole thing took
var totalMilliseconds = 0.0;
foreach (var log in logs)
{
  totalMilliseconds = totalMilliseconds + log.TotalMilliseconds;
}
Console.WriteLine($"Runtime: {stopwatch.Elapsed.TotalMilliseconds}, Execution: {totalMilliseconds}");

MyExtensions.cs

namespace System.Threading.Tasks
{
  public static class MyExtensions
  {
    public static async Task<T> ExecuteAsync<T>(this Task<T> code, Details details)
    {
      T result = default(T);

      Stopwatch stopwatch = Stopwatch.StartNew();
      code.Start();
      await code.ConfigureAwait(false);

      result = code.Result;
      stopwatch.Stop();

      return result;
    }
  }

  // The following class is only for debugging purposes
  public class Details
  {
     public int SleepTime { get; set; }

     public double TotalMilliseconds { get; set; }
  }
}

当我 运行 这个应用程序时,我在终端 window 中看到如下内容:

6 + 10 = 16 (over 44 ms.)
6 + 10 = 16 (over 197 ms.)
6 + 10 = 16 (over 309 ms.)
6 + 10 = 16 (over 687 ms.)
6 + 10 = 16 (over 950 ms.)
Result: 16
Result: 16
Result: 16
Result: 16
Result: 16
Runtime: 3.5835, Execution: 2204.62970000004

根据此输出,似乎我有五个异步任务 运行ning。睡眠时间每次都会改变(这很好)。 运行 时间小于执行时间,这意味着任务 运行 是并行的。但是,这几乎就像任务在 'for' 循环完成后得到 运行 。这是我唯一能看到 6 来源的地方。但是,我不明白为什么,或者如何解决它。结果应该更像:

4 + 10 = 14 
5 + 10 = 15 
2 + 10 = 12 
3 + 10 = 13 
1 + 10 = 11

我做错了什么?为什么每次都使用相同的 i 值?我该如何解决这个问题?

非常感谢您的帮助!

i 的值不是函数的局部值,也就是 mem 分配是相同的,所以它发生了变化。

for (var i=1; i<=5; i++)
{
    var shouldBe = i + offset;
    var d = new Details();

    var t = new Task<int>(() => {
    var ms = random.Next(1001);    // Choose a wait time between 0 and 1 seconds
    Thread.Sleep(ms);
    d.SleepTime = ms;

    var result = i + offset;
    Console.WriteLine($"{i} + {offset} = {result}  (over {timeout} ms.)");
    return result;
    });

    tasks.Add(t.ExecuteAsync<int>());
    details.Add(d);
}

这应该可以正确打印

for (var i=1; i<=5; i++)
{
    var localCounter = i;
    var shouldBe = localCounter + offset;
    var d = new Details();

    var t = new Task<int>(() => {
        var ms = random.Next(1001);    // Choose a wait time between 0 and 1 seconds
        Thread.Sleep(ms);
        d.SleepTime = ms;

        var result = localCounter + offset;
        Console.WriteLine($"{localCounter} + {offset} = {result}  (over {timeout} ms.)");
        return result;
    });

    tasks.Add(t.ExecuteAsync<int>()); //<- this extention method is just making it more completcated to read. i would remove it.
    details.Add(d);
}

这应该有助于一个桶

static async Task Main(string[] args)
{

    var random = new Random();
    List<Task<Details>> tasks = new List<Task<Details>>();
    for (var i = 1; i <= 20; i++)
    {
        var localCounter = i;

        var t = new Task<Details>(() => {
            var ms = random.Next(1001);
            Task.Delay(ms);
            var result = new Details
            {
                Id = localCounter,
                DelayTime = ms
            };
            Console.WriteLine($"basically done id: {localCounter}");
            return result;
        });

        tasks.Add(t);
    }

    tasks.ForEach(t => t.Start());
    Task.WaitAll(tasks.ToArray());
    foreach (var item in tasks)
    {
        Console.WriteLine($"id: {item.Result.Id}");
        Console.WriteLine($"random delay: {item.Result.DelayTime}");
    }
}