LINQ 可枚举线程

发布于 2024-10-26 18:41:09 字数 750 浏览 1 评论 0原文

我试图了解 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

愛上了 2024-11-02 18:41:09

您的问题与线程无关。当第二次枚举threads时,您的查询将被第二次执行并创建第二组线程。

因此,您.Start一组线程,然后.Join另一组线程。您需要急切地评估查询一次,然后缓存结果。

IEnumerable<Thread> lazyThreads = Enumerable.Range(...
Thread[] threads=lazyThreads.ToArray();//Evaluate and store in an array

您也可以将其写为单个语句:

var threads = Enumerable.Range(1,50).Select(...).ToArray();

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.

IEnumerable<Thread> lazyThreads = Enumerable.Range(...
Thread[] threads=lazyThreads.ToArray();//Evaluate and store in an array

You can also write it as a single statement:

var threads = Enumerable.Range(1,50).Select(...).ToArray();
缺⑴份安定 2024-11-02 18:41:09

threads 变量是一个查询,而不是线程列表。每次迭代它时,都会再次执行查询,因此在第二种情况下,您将调用 Join() 而无需调用 Start()

您可以在查询末尾添加 ToList() 以使其成为列表:

 var threads = Enumerable.Range(0, 50).Select(x =>{ ... }).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 calling Join() without calling Start().

You can add ToList() at the end of the query to make it a list:

 var threads = Enumerable.Range(0, 50).Select(x =>{ ... }).ToList();
说好的呢 2024-11-02 18:41:09

您将 lambda 表达式枚举两次(惰性枚举) - 因此,您的第二个 foreach 将迭代与第一个线程不同的线程。

尝试

var threads = Enumerable.Range(0, 50).Select( ... ).ToList();

foreach(var thread in threads)
...

调用 ToList() 将创建一个包含线程的列表,您可以随后多次枚举该列表。

You are enumerating the lambda expression twice (lazy enumeration) - your second foreach is therefore iterating through different threads from the first.

Try

var threads = Enumerable.Range(0, 50).Select( ... ).ToList();

foreach(var thread in threads)
...

Calling ToList() will create a list with the threads over which you can subsequently enumerate multiple times.

π浅易 2024-11-02 18:41:09

在这种情况下,您并没有真正探索 LINQ 如何处理线程。相反,您可以使用链接来节省几行代码,同时自己处理线程。

从 .Net 4.0 开始,LINQ 提供了一些开箱即用的简洁线程帮助。研究并行 LINQ。另请查看并行扩展

至于您碰巧使用 LINQ 的老式线程处理,您的问题实际上是由于您使用 LINQ 造成的。您的问题与 延迟有关执行。在调试模式下,在该行完成后将鼠标悬停在 threads 变量上。您会看到它是一个查询,而不是一个简单的集合。每次访问该变量时,它都会重新获取它的值。

修复方法很简单也很常见:只需在第一行末尾添加 .ToList() 即可。然后,您的隐式类型 threads 变量将是一个简单的列表,并按照您的预期运行。

var threads = Enumerable.Range(0, 50).Select(x =>
                                 {
                                     Thread thread = new Thread(Method);
                                     thread.Name = x.ToString();
                                     return thread;
                                 }).ToList();

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.

var threads = Enumerable.Range(0, 50).Select(x =>
                                 {
                                     Thread thread = new Thread(Method);
                                     thread.Name = x.ToString();
                                     return thread;
                                 }).ToList();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文