为什么循环中的任务工厂打印超出循环索引?
Why task factory in loop prints beyond loop index?
我正在学习使用C#中的Task Parallel Library(TPL),并编写了以下代码(您可以复制粘贴并运行)。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace parallelTaskLibrary
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 6; i++)
{
var t01 = Task.Factory.StartNew(() => Console.WriteLine("in loop: i = {0}", i));
}
Console.WriteLine("press any key to terminate...");
Console.ReadKey();
}
}
}
在 for
循环中,计数器索引 i
无法启动值为 i = 6
的迭代。然而,我得到的输出是这样的:
press any key to terminate...
in loop: i = 6
in loop: i = 6
in loop: i = 6
in loop: i = 6
in loop: i = 6
in loop: i = 6
然而,在另一次发布中(代码没有改变),我得到了这个:
in loop: i = 1
in loop: i = 1
in loop: i = 2
in loop: i = 3
in loop: i = 4
in loop: i = 5
press any key to terminate...
这是合理的...
我调试了代码,发现i
的值是:0,1,3,4,5,6
这是怎么发生的?
为什么我在循环中得到 (i = 6)?
我的代码有什么问题吗?
注:我用的是visual studio2010
显然,您将在执行代码(带有 Console.WriteLine 语句的委托)时打印 "i" 的值,这很可能在 稍后.
这可能就是您想要的:
for (int i = 0; i < 6; i++)
{
var j = i;
var t01 = Task.Factory.StartNew(() => Console.WriteLine("in loop: i = {0}", j));
}
>我的代码有什么问题吗?
是:-)
因为存在闭包问题。您需要将变量 i
复制到临时变量中。
for (int i = 0; i < 6; i++)
{
var tempi = i;
var t01 = Task.Factory.StartNew(() => Console.WriteLine("in loop: i = {0}", tempi));
}
因为您的任务在另一个线程中启动。但是你不要在当前线程中等待那个任务。所以程序会回来并增加计数器。由于您创建的委托使用原始计数器,因此它会打印 6
。因为数到 6 比创建新任务快得多。
当您使用调试器时,新任务将有机会在您继续递增计数器之前打印该值,
有了该代码,您就有了一个工作示例,说明了您在编程时必须注意的事项 multi-threaded-applications
。问题是启动一个 thead 需要一些时间,此时主线程完成对 for-loop
的迭代。在主线程完成 i == 6
并且每个线程访问 i
的值时,该值是 6。解决方案是创建一个局部变量并复制 i
[= 的值16=]
for(...)
{
int temp = i;
var t1 //.....
}
for (int i = 0; i < 6; i++)
从 C# 2012 开始,以下代码将按您预期的方式工作:
foreach (int i in Enumerable.Range(0, 6))
http://ideone.com/naaZNx - 示例。
在循环内声明变量是 breaking changes in VS2012.
之一
为什么我在循环中得到 (i = 6)?
所有步骤:
i=0
i<6 => create Thread1
i++ => i=1
i<6 => create Thread2
i++ => i=2
i<6 => create Thread3
i++ => i=3
i<6 => create Thread4
i++ => i=4
i<6 => create Thread5
i++ => i=5
i<6 => create Thread6
i++ => i=6
i<6 NO => leave for
主线程执行:
Console.WriteLine("press any key to terminate...");
创建的所有 6 个线程都执行:
Console.WriteLine("in loop: i = {0}", i)
其中 i=6
我正在学习使用C#中的Task Parallel Library(TPL),并编写了以下代码(您可以复制粘贴并运行)。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace parallelTaskLibrary
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 6; i++)
{
var t01 = Task.Factory.StartNew(() => Console.WriteLine("in loop: i = {0}", i));
}
Console.WriteLine("press any key to terminate...");
Console.ReadKey();
}
}
}
在 for
循环中,计数器索引 i
无法启动值为 i = 6
的迭代。然而,我得到的输出是这样的:
press any key to terminate...
in loop: i = 6
in loop: i = 6
in loop: i = 6
in loop: i = 6
in loop: i = 6
in loop: i = 6
然而,在另一次发布中(代码没有改变),我得到了这个:
in loop: i = 1
in loop: i = 1
in loop: i = 2
in loop: i = 3
in loop: i = 4
in loop: i = 5
press any key to terminate...
这是合理的...
我调试了代码,发现i
的值是:0,1,3,4,5,6
这是怎么发生的?
为什么我在循环中得到 (i = 6)?
我的代码有什么问题吗?
注:我用的是visual studio2010
显然,您将在执行代码(带有 Console.WriteLine 语句的委托)时打印 "i" 的值,这很可能在 稍后.
这可能就是您想要的:
for (int i = 0; i < 6; i++)
{
var j = i;
var t01 = Task.Factory.StartNew(() => Console.WriteLine("in loop: i = {0}", j));
}
>我的代码有什么问题吗?
是:-)
因为存在闭包问题。您需要将变量 i
复制到临时变量中。
for (int i = 0; i < 6; i++)
{
var tempi = i;
var t01 = Task.Factory.StartNew(() => Console.WriteLine("in loop: i = {0}", tempi));
}
因为您的任务在另一个线程中启动。但是你不要在当前线程中等待那个任务。所以程序会回来并增加计数器。由于您创建的委托使用原始计数器,因此它会打印 6
。因为数到 6 比创建新任务快得多。
当您使用调试器时,新任务将有机会在您继续递增计数器之前打印该值,
有了该代码,您就有了一个工作示例,说明了您在编程时必须注意的事项 multi-threaded-applications
。问题是启动一个 thead 需要一些时间,此时主线程完成对 for-loop
的迭代。在主线程完成 i == 6
并且每个线程访问 i
的值时,该值是 6。解决方案是创建一个局部变量并复制 i
[= 的值16=]
for(...)
{
int temp = i;
var t1 //.....
}
for (int i = 0; i < 6; i++)
从 C# 2012 开始,以下代码将按您预期的方式工作:
foreach (int i in Enumerable.Range(0, 6))
http://ideone.com/naaZNx - 示例。
在循环内声明变量是 breaking changes in VS2012.
之一为什么我在循环中得到 (i = 6)?
所有步骤:
i=0
i<6 => create Thread1
i++ => i=1
i<6 => create Thread2
i++ => i=2
i<6 => create Thread3
i++ => i=3
i<6 => create Thread4
i++ => i=4
i<6 => create Thread5
i++ => i=5
i<6 => create Thread6
i++ => i=6
i<6 NO => leave for
主线程执行:
Console.WriteLine("press any key to terminate...");
创建的所有 6 个线程都执行:
Console.WriteLine("in loop: i = {0}", i)
其中 i=6