Может кто-нибудь объяснить логику цикла Parallel.ForEach, которая здесь происходит? - PullRequest
0 голосов
/ 28 ноября 2018

Я просто пытаюсь изучить различные способы выполнения потоков / задач, и мне нужен был способ динамического изменения выполняемых задач, и я указал на цикл Parallel.ForEach.Я сделал небольшой пример программы и у меня есть несколько вопросов.

public void StartTest()
{
    List<Action> actions = new List<Action>();
    for (int i = 0; i < 6; i++)     
    {
        actions.Add(() => Function1("Word: " + i));
    }
    Parallel.ForEach(actions, new ParallelOptions
    {
        MaxDegreeOfParallelism = 2
    }, action => action());

    Console.WriteLine("Finished. \nTime Taken: " + total.ToString(@"dd\.hh\:mm\:ss"));
    Console.Read();
}


private void Function1(string word)
{
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine(word + " |  Task Id: " + Task.CurrentId + " |   " + i);
    }
    Console.WriteLine(word + " ----- Completed.");
}

Итак, мой первый вопрос: что делает фрагмент цикла action => action ()?Я понимаю, что такое лямбды, но я действительно не следую этому

Мой второй вопрос: почему это результат?

Слово: 6 |Task Id: 3 |0

Слово: 6 |Task Id: 3 |1

Слово: 6 |Task Id: 3 |2

Слово: 6 |Task Id: 3 |3

Слово: 6 |Task Id: 3 |4

Слово: 6 ----- Завершено.

Слово: 6 |Task Id: 3 |0

Слово: 6 |Task Id: 3 |1

Слово: 6 |Task Id: 3 |2

Слово: 6 |Task Id: 3 |3

Слово: 6 |Task Id: 3 |4

Слово: 6 ----- Завершено.

Слово: 6 |Task Id: 3 |0

Слово: 6 |Task Id: 3 |1

Слово: 6 |Task Id: 3 |2

Слово: 6 |Task Id: 3 |3

Слово: 6 |Task Id: 3 |4

Слово: 6 ----- Завершено.

Слово: 6 |Task Id: 3 |0

Слово: 6 |Task Id: 3 |1

Слово: 6 |Task Id: 3 |2

Слово: 6 |Task Id: 3 |3

Слово: 6 |Task Id: 3 |4

Слово: 6 ----- Завершено.

Слово: 6 |Task Id: 3 |0

Слово: 6 |Task Id: 3 |1

Слово: 6 |Task Id: 3 |2

Слово: 6 |Task Id: 2 |0

Слово: 6 |Task Id: 2 |1

Слово: 6 |Task Id: 2 |2

Слово: 6 |Task Id: 2 |3

Слово: 6 |Task Id: 2 |4

Слово: 6 ----- Завершено.

Слово: 6 |Task Id: 3 |3

Слово: 6 |Task Id: 3 |4

Слово: 6 ----- Завершено.

Завершено.

Время выполнения: 00.00: 00: 00

Почему каждый номер6?Я понимаю, как работает многопоточность, но не передача / ссылка на параметры.

Итак, это мои два вопроса.Любая помощь будет фантастической.Я некоторое время искал в Google и не смог найти никакой документации, которая имела бы для меня смысл.

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018
public void StartTest()
{
    var actions = new List<Action>();
    for (int i = 0; i < 6; i++)
    {
        // you can't pass 'i' directly to the Action here,
        // because 'i' is in the scope of where the Action is executed
        // and since the parameter of the Action is first evaluated at the 
        // execution of the Action if you were to put 'i' it checks what value
        // 'i' has at the current point in time and since the for-loop finished
        // already it is always going to be 6
        var word = $"Word: {i}";
        actions.Add(() => Function1(word));
    }

    // you could interpret the lambda 'action => action()' as
    // foreach(var action in actions)
    //     action();
    // so it essentially tells you what it's going to do for each
    // Action Item in the Action-Collection you passed as Parallel.ForEach's first parameter,
    // while 'action' represents the "current" item
    Parallel.ForEach(actions, new ParallelOptions{MaxDegreeOfParallelism = 2}, action => action());

    Console.WriteLine("Finished. \nTime Taken: " + total.ToString(@"dd\.hh\:mm\:ss"));
    Console.Read();
}


private void Function1(string word)
{
    for (int i = 0; i < 5; i++)
        Console.WriteLine(word + " |  Task Id: " + Task.CurrentId + " |   " + i);

    Console.WriteLine(word + " ----- Completed.");
}
0 голосов
/ 28 ноября 2018

Относительно первого вопроса:

что делает блок "action => action ()" цикла?

Это то, что будетвызывается для каждого элемента в списке actions.

Более формально это называется телом Paraller.ForEach, и это делегат, который вызывается один раз за итерацию.Для получения дополнительной информации, пожалуйста, посмотрите здесь .

По второму вопросу:

Сначала вы должны захватить переменную i, используя другую переменную внутри блокаоператора for, прежде чем использовать его в лямбда-выражении, которое вы создаете, как показано ниже:

for (int i = 0; i < 6; i++)     
{
    var j = i; 
    actions.Add(() => Function1("Word: " + j));
}

Вы можете найти подробное объяснение, почему вы должны сделать это здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...