开始在foreach循环
一个新的线程我有对象的名单,我想遍历该列表,并开始一个新的线程,传递当前对象。开始在foreach循环
我已经写了什么,我觉得应该这样做的例子,但它不工作。具体来说,似乎线程在每次迭代中都被覆盖。这并没有真正意义的我,但因为我每次做一个新的Thread对象。
这是测试代码,我写
class Program
{
static void Main(string[] args)
{
TestClass t = new TestClass();
t.ThreadingMethod();
}
}
class TestClass
{
public void ThreadingMethod()
{
var myList = new List<MyClass> { new MyClass("test1"), new MyClass("test2") };
foreach(MyClass myObj in myList)
{
Thread myThread = new Thread(() => this.MyMethod(myObj));
myThread.Start();
}
}
public void MyMethod(MyClass myObj) { Console.WriteLine(myObj.prop1); }
}
class MyClass
{
public string prop1 { get; set; }
public MyClass(string input) { this.prop1 = input; }
}
我的机器上输出是
test2
test2
,但我希望它是
test1
test2
我试图改变螺纹线到
ThreadPool.QueueUserWorkItem(x => this.MyMethod(myObj));
但没有一个线程的开始。
我想我只是有一个关于线程应该如何工作的误解。有人能指出我正确的方向并告诉我我做错了什么吗?
这是因为你关闭了一个变量在错误的范围。这里的解决方案是使用临时在您的foreach循环:
foreach(MyClass myObj in myList)
{
MyClass tmp = myObj; // Make temporary
Thread myThread = new Thread(() => this.MyMethod(tmp));
myThread.Start();
}
有关详细信息,我建议你阅读关于这个确切的主题埃里克利珀的帖子:Closing over the loop variable considered harmful
你打我吧! – 2012-02-23 18:04:45
这是一个快速反应。哇。 – BlueM 2012-02-23 18:06:00
嘎,我踢了自己,因为我实际上阅读[这个问题](http://stackoverflow.com/q/8898925/817630)上个月是答案。我甚至看过Eric的博客文章。谢谢你指出我应该记得我自己。 – 2012-02-23 18:18:48
的问题是,您使用的是最新的值你的封闭内部的对象。所以,线程的每次调用都会看到相同的值。要解决此问题,请将该值复制到局部变量中:
foreach(MyClass myObj in myList)
{
MyClass localCopy = myObj;
Thread myThread = new Thread(() => this.MyMethod(localCopy));
myThread.Start();
}
同意里德的回答(+1)。
我想补充一点,如果你是.NET 4,你可能想看看任务并行库来解决这一类的问题。专门针对这种情况,看看Parallel.ForEach()。
虽然我喜欢Parallel.ForEach,但它意识到它本身就是一种阻塞方法,OP的“火和遗忘” - 因此使用它有一个功能差异。 – 2012-02-23 18:09:45
如果顺序没有关系比去
Parallel.ForEach(myList, obj => this.MyMethod(obj));
Parallel.ForEach本身是一种阻塞方法,其中OP的“火灾和遗忘” - 因此使用它有一个功能差异。在这种情况下,这可能不合适(至少不是没有将它放入任务本身) – 2012-02-23 18:14:04
我更喜欢这种方式:
public void ThreadingMethod()
{
var myList = new List<MyClass> { new MyClass("test1"), new MyClass("test2") };
Parallel.ForEach(myList, new ParallelOptions() { MaxDegreeOfParallelism = 100 },
(myObj, i, j) =>
{
MyMethod(myObj);
});
}
虽然没有测试....
Parallel.ForEach具有与OP方法不同的功能行为。原始代码具有“火灾和遗忘”行为,而这将阻止调用线程,直到操作完成。另外,我不建议设置MaxDegreeOfParallelism,除非有特定的理由这样做。 – 2012-02-23 19:17:07
@ReedCopsey - 我想你只是假设。使用Parallel.ForEach始终是在您的应用程序中实现PROPER线程的首选方法,尤其是当您有大量要处理的项目(同时)并且没有足够的资源来使用简单的Thread()时。如果他用你建议的方法使用1000个线程,那么它的实现非常糟糕。 – SolidSnake 2012-02-23 19:52:06
Parallel.ForEach并不总是首选的方法。这是一个很好的选择,但是其中之一。使用任务或ThreadPool通常比自己管理线程更好,但即使如此,有时直接使用Thread仍是首选。 OP代码中没有足够的信息来暗示Parallel.ForEach将是首选。 (虽然我几乎总是选择一个长时间运行的Task,而不是手动管理的Thread) – 2012-02-23 20:12:48
你的生活会所以容易得多,如果你检查出的并行扩展库中的.Net 3.5推出。这里有一个地方开始:http://msdn.microsoft.com/en-us/library/dd460693%28VS.100%29.aspx – DOK 2012-02-23 18:04:59
http://www.albahari.com/threading/ – 2017-10-31 06:28:42