LINQ Enumerable Threading - PullRequest
       7

LINQ Enumerable Threading

1 голос
/ 25 марта 2011

Я пытаюсь понять, как 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);

Ответы [ 4 ]

9 голосов
/ 25 марта 2011

Ваша проблема не связана с потоками. При перечислении 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();
4 голосов
/ 25 марта 2011

Переменная threads представляет собой запрос , а не список потоков. Каждый раз, когда вы выполняете итерацию, вы выполняете запрос снова, поэтому во втором случае вы вызываете Join() без вызова Start().

Вы можете добавить ToList() в конце запроса, чтобы сделать его списком:

 var threads = Enumerable.Range(0, 50).Select(x =>{ ... }).ToList();
2 голосов
/ 25 марта 2011

Вы дважды перечисляете лямбда-выражение (ленивое перечисление) - поэтому ваш второй foreach перебирает различные потоки из первого.список с потоками, которые вы можете впоследствии перечислить несколько раз.

1 голос
/ 25 марта 2011

В этом случае вы на самом деле не исследуете, как LINQ справляется с многопоточностью.Скорее, вы используете ссылку, чтобы сохранить несколько строк кода при работе с потоками самостоятельно.

Начиная с .Net 4.0, LINQ оказывает некоторую полезную помощь по созданию потоков из коробки.Исследуйте Parallel LINQ .Также обратите внимание на Parallel Extensions .

Что касается вашей старомодной обработки потоков, с которой вы случайно используете 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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...