【问题标题】:Using Task.Factory.StartNew in a loop在循环中使用 Task.Factory.StartNew
【发布时间】:2015-11-23 19:46:04
【问题描述】:

我正在尝试掌握 .NET 中的多线程编程。

我想在一个 for 循环中创建 100 个任务,每个任务会休眠 1 秒,然后输出创建它时使用的 i 和它的托管线程 ID。所有任务完成后,我想输出经过的总时间。

所以我正在运行这个简单的代码

    private static void Main(string[] args)
    {
        List<Task> tasks = new List<Task>();

        for (int i = 0; i < 100; i++)
        {
            tasks.Add(Task.Factory.StartNew(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine(i.ToString() + "  " + Thread.CurrentThread.ManagedThreadId);
            }));
        }
        Stopwatch watch = new Stopwatch();

        watch.Start();
        var final = Task.Factory.ContinueWhenAll(tasks.ToArray(), doneTasks =>
        {
            watch.Stop();
            Console.WriteLine("done in {0}", watch.Elapsed);
        });
        Console.ReadKey();
    }

我得到的输出:

100  24
100  23
...
100  14
100  25
done in 00:00:12.0044853

我不明白为什么所有的 i 都是一样的,为什么是 100?直觉上,我希望它们是 0~99,但不是全是 100。

【问题讨论】:

  • 仅供参考:在任务上下文中,请使用 await Task.Delay() 而不是 Thread.Sleep。

标签: c# multithreading task


【解决方案1】:

想象一下执行的顺序。您指示每个任务在一秒钟后输出i,但此时循环已完成执行且i 等于100。

您可以使用以下 StartNew 重载来传递将由您的操作使用的 state 对象:

public Task StartNew(Action<object> action, object state)

然后执行以下操作:

for (int i = 0; i < 100; i++)
{
    tasks.Add(Task.Factory.StartNew(o =>
    {
        int value = (int)o;

        Thread.Sleep(1000);
        Console.WriteLine(value.ToString() + "  " + Thread.CurrentThread.ManagedThreadId);
    }, i));
}

【讨论】:

    【解决方案2】:

    那是因为你的任务是在你的闭包被执行之前创建的。如果您在 sleep 调用之前将 I 的值复制到变量中,或者更好的是,将其作为参数传递给您的操作,您应该会得到所需的结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-06
      • 2015-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多