Выполнить несколько задач с продолжением - PullRequest
0 голосов
/ 28 июня 2018

Я обнаружил странное поведение при выполнении задач внутри цикла for и ожидании их всех. Как упомянуто ниже, код выполняет запуск цикла для определенного количества задач, каждая задача создает элемент «ToDo», и у каждой задачи есть продолжение, которое назначает человеку каждую созданную задачу и, наконец, но их в listBox, используя Вызывать так, что поток пользовательского интерфейса называется. это работает нормально, но я не получаю ожидаемых данных в listBox. Я не ожидаю, что они будут заказаны, но я ожидаю, что они будут в паре, например :

Персона_8, Todo 8 Человек 5, Todo 5 и т.д ...

И, конечно, они должны появляться только в списке. Но вместо этого я получаю странный вывод (и вывод никогда не бывает одинаковым для каждого прогона), вот несколько примеров выполнения кода:

введите описание изображения здесь введите описание изображения здесь

А вот и код:

private async void buttonCreateToDo_Click(object sender, EventArgs e){
    await CreateToDoAsync();
}

private async Task CreateToDoAsync(){
    List<Task> taskList = new List<Task>();
    for (int i = 1; i < 10; i++){
        var task = Task.Run(() => CreateToDo(i));
        Task continuation = task.ContinueWith((antecedent) => Invoke(new AssignTaskDelegate(AssignTask), (new Person() {
            Name = $"Person_{i}",
            ToDoForPerson = antecedent.Result
        })));
        taskList.Add(task);

    }
    await Task.WhenAll(taskList.ToArray());
}

private ToDo CreateToDo(int toDoId) {
    return new ToDo(){
        Id = toDoId,
        Description = $"Todo {toDoId}"
    };
}

private void AssignTask(Person person){
    listBoxToDo.Items.Add($"{person.Name}, {person.ToDoForPerson.Description}");
}

Ответы [ 2 ]

0 голосов
/ 28 июня 2018

Ваша проблема в том, что цикл for работает намного быстрее, чем создание задач, и поэтому к моменту запуска задач переменная i уже достигла конца цикла.

Чтобы исправить это, вам нужно взять копию i внутри цикла и использовать ее.

Попробуйте этот код:

private async Task CreateToDoAsync()
{
    List<Task> taskList = new List<Task>();
    for (int i = 1; i < 10; i++)
    {
        var local_i = i;
        var task = Task.Run(() => CreateToDo(local_i));
        Task continuation = task.ContinueWith((antecedent) => Invoke(new AssignTaskDelegate(AssignTask), (new Person()
        {
            Name = $"Person_{local_i}",
            ToDoForPerson = antecedent.Result
        })));
        taskList.Add(task);
    }
    await Task.WhenAll(taskList.ToArray());
}

Теперь предпочтительнее использовать Microsoft Reactive Framework (NuGet «System.Reactive») для этой работы. Ваш код будет выглядеть так:

private async Task CreateToDoAsync()
{
    var query =
        from i in Observable.Range(1, 9)
        from t in Observable.Start(() => CreateToDo(i))
        select new Person() { Name = $"Person_{i}", ToDoForPerson = t };

    await query.ObserveOn(listBoxToDo).Do(x => AssignTask(x));
}

Готово. Вот и все.

Когда я запускаю свой код (с выводом AssignTask на консоль), я получаю это:

Person_1, Todo 1
Person_2, Todo 2
Person_3, Todo 3
Person_6, Todo 6
Person_7, Todo 7
Person_4, Todo 4
Person_5, Todo 5
Person_8, Todo 8
Person_9, Todo 9

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * .ObserveOn(listBoxToDo) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *. "*1020*."

0 голосов
/ 28 июня 2018

Вы используете переменную "i" из цикла внутри задачи. «i» могло измениться во время запуска вашей задачи.

...