【问题标题】:Task in .Net 4.0 [duplicate].Net 4.0中的任务[重复]
【发布时间】:2023-03-28 18:44:01
【问题描述】:

我正在尝试使用 .Net 4.0 c# 中的 Task 进行并行编程。

我的程序的输出有点混乱。

 class Program
    {
        static void Main(string[] args)
        {

            List<Task> lstTasks =  new List<Task>();
            for (int i = 0; i < 5; i++)
            {
                Task tsk = Task.Factory.StartNew(() => DoSomething(i.ToString()));
                lstTasks.Add(tsk);
            }

            Task.WaitAll(lstTasks.ToArray());
            Console.WriteLine("Done");
            Console.ReadLine();
        }

        static void DoSomething(string tasKname)
        {
            Console.WriteLine(tasKname);
            System.Threading.Thread.Sleep(10000);
        }
    }

输出是

5
5
5
5
5
Done.

我期待。

0
1
2
3
4
Done.

我哪里出错了?

【问题讨论】:

  • 这是重复的吗??我不这么认为...

标签: c# .net c#-4.0 multitasking


【解决方案1】:

您在定义函数() =&gt; DoSomething(i.ToString()) 时创建了closure。

闭包是一个匿名函数/lamdba,它引用在创建闭包的方法中定义的一些变量。在你的情况下,这是变量i。

当这个函数被执行时,它将使用i的当前值,而不是i在你创建它时的值。

您必须注意,调用Task.Factory.StartNew 不会立即开始执行任务。在您的情况下,任务在 for 循环之后开始执行,因此 i 的值为 5。

要获得您期望的结果,请在循环中使用一个单独的变量来存储i 的当前值。

for (int i = 0; i < 5; i++)
{
    int k = i;
    Task tsk = Task.Factory.StartNew(() => DoSomething(k.ToString()));
    lstTasks.Add(tsk);
}

不过,您不应期望结果按任何特定顺序排列。

【讨论】:

  • 您的解决方案运行良好......但我不明白试图解释我的概念......你能详细解释一下吗?
  • @Manish 我为我的答案添加了更多解释。我错过了原始答案中的一件重要事情 - Task.Factory.StartNew 不会立即开始执行任务。
  • 是什么让你这么说..直到for循环完成任务才执行?
  • @Manish StartNew 将任务添加到线程池队列并返回。然后线程池将任务分配给一个线程。当操作系统安排它运行时,线程将运行。这一切都需要一些时间,足以完成for 循环的执行。您可以通过在循环后添加另一个Console.Writeline() 来测试它。
【解决方案2】:

您正在访问一个在循环中发生变化的变量。从本质上讲,您的foreach 运行得非常快,当DoSomething 运行时,i 是 5。试试这个:

for (int i = 0; i < 5; i++)
{
    Task tsk = Task.Factory.StartNew(() => DoSomething(i.ToString()));
    lstTasks.Add(tsk);
    Thread.Sleep(50);
}

您应该会在控制台中看到预期的输出。


你说I'm expecting 0 1 2 3 4。但你不应该。任务最重要的方面是您不知道它们何时会完成。例如,当我更改您的代码以使用 Parallel.Foreach() 时:

Parallel.ForEach(Enumerable.Range(0, 5), i =>
{
    Task tsk = Task.Factory.StartNew(() => DoSomething(i.ToString()));
    lstTasks.Add(tsk);
});

我得到了预期的数字,从 0 到 4,但每次我运行代码时都是随机顺序,因为我们使用的是 Tasks,它们都彼此独立运行。

【讨论】:

  • 你是正确的..任何 0.4 的顺序都可以..但不是 5.5.5.5.5
  • 但我不想在 for 循环中添加睡眠。@jakub 方法工作正常
  • 我绝对不建议在你的代码中睡觉,这是一个演示。如果你的代码这么简单,你根本不需要任务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多