LINQ 可枚举线程
我试图了解 LINQ 如何处理线程。以下代码生成 ThreadStateException“线程尚未启动”。为什么会出现这种情况?
var threads = Enumerable.Range(0, 50).Select(x =>
{
Thread thread = new Thread(Method);
thread.Name = x.ToString();
return thread;
});
foreach (var thread in threads)
{
thread.Start();
}
foreach (var thread in threads)
{
thread.Join();
}
Console.WriteLine(j);
I'm trying to understand how LINQ deals with threading. The following code generates ThreadStateException "Thread has not been started". Why this happens?
var threads = Enumerable.Range(0, 50).Select(x =>
{
Thread thread = new Thread(Method);
thread.Name = x.ToString();
return thread;
});
foreach (var thread in threads)
{
thread.Start();
}
foreach (var thread in threads)
{
thread.Join();
}
Console.WriteLine(j);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您的问题与线程无关。当第二次枚举
threads
时,您的查询将被第二次执行并创建第二组线程。因此,您
.Start
一组线程,然后.Join
另一组线程。您需要急切地评估查询一次,然后缓存结果。您也可以将其写为单个语句:
Your problem is unrelated to threading. When enumeration
threads
the second time your query is executed a second time and creates a second set of threads.So you
.Start
one set of threads, and.Join
another. You need to eagerly evaluate the query once, and then cache the result.You can also write it as a single statement:
threads
变量是一个查询,而不是线程列表。每次迭代它时,都会再次执行查询,因此在第二种情况下,您将调用Join()
而无需调用Start()
。您可以在查询末尾添加
ToList()
以使其成为列表:The
threads
variable is a query, not a list of threads. Each time you iterate over it, you execute the query over again, so in the second case, you are callingJoin()
without callingStart()
.You can add
ToList()
at the end of the query to make it a list:您将 lambda 表达式枚举两次(惰性枚举) - 因此,您的第二个 foreach 将迭代与第一个线程不同的线程。
尝试
调用 ToList() 将创建一个包含线程的列表,您可以随后多次枚举该列表。
You are enumerating the lambda expression twice (lazy enumeration) - your second foreach is therefore iterating through different threads from the first.
Try
Calling ToList() will create a list with the threads over which you can subsequently enumerate multiple times.
在这种情况下,您并没有真正探索 LINQ 如何处理线程。相反,您可以使用链接来节省几行代码,同时自己处理线程。
从 .Net 4.0 开始,LINQ 提供了一些开箱即用的简洁线程帮助。研究并行 LINQ。另请查看并行扩展。
至于您碰巧使用 LINQ 的老式线程处理,您的问题实际上是由于您使用 LINQ 造成的。您的问题与 延迟有关执行。在调试模式下,在该行完成后将鼠标悬停在 threads 变量上。您会看到它是一个查询,而不是一个简单的集合。每次访问该变量时,它都会重新获取它的值。
修复方法很简单也很常见:只需在第一行末尾添加 .ToList() 即可。然后,您的隐式类型 threads 变量将是一个简单的列表,并按照您的预期运行。
In this case, you're not really exploring how LINQ deals with threading. Rather, you're using link to save a few lines of code while dealing with threading yourself.
Beginning with .Net 4.0, LINQ does some neat threading help out of the box. Investigate Parallel LINQ. Also check out the Parallel Extensions.
As for your old fashioned thread handling, with which you happen to be using LINQ, your problem actually does results from your use of LINQ. You're problem has to do with delayed execution. In debug mode, hover of the threads variable after that line is done. You'll see it's a query, not a simple collection. Every time you access this variable, it will get it's values afresh.
The fix is easy and very common: Just add .ToList() at the end of the first line. Your implicitly typed threads variable will then be a simple list, and behave as you expect.