简体   繁体   English

连续运行多个任务

[英]Run multiple tasks with continuation

I found some strange behavior running tasks within a for loop and awaiting them all. 我发现一些奇怪的行为在for循环中运行任务并等待它们。 As mentioned below, what the code does is starting a "loop" for definite number of tasks, each task creates a "ToDo" item and each task has a continuation that assigns each created task to a person and finally but them in a listBox using Invoke so the UI thread is called. 如下所述,代码的作用是为一定数量的任务启动一个“循环”,每个任务创建一个“ ToDo”项目,每个任务都有一个延续,将每个创建的任务分配给一个人,最后将它们分配给listBox调用以便调用UI线程。 this works fine, but i do not get the expected data in the listBox. 这工作正常,但我没有在listBox中获得预期的数据。 I do not expect them to be ordered, but i do expect them to be paired, eg : 我不希望他们被订购,但我确实希望它们能够配对,例如:

Person_8, Todo 8 Person 5, Todo 5 etc... Person_8,Todo 8 Person 5,Todo 5等等...

And they should only appear ones in the listBox of course ! 而且它们应该只出现在listBox中! But instead, i get strange output (and output is never the same for each run), here are some examples running the code: 但是,相反,我得到了奇怪的输出(每次运行的输出都不相同),下面是一些运行代码的示例:

enter image description here enter image description here 在此处 输入图像描述在 此处 输入图像描述

And here is the code: 这是代码:

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}");
}

Your issue is that for loop runs much faster than the creation of the tasks and so by the time the tasks run the variable i has reached the end of the loop. 您的问题是for循环的运行要比任务的创建快得多,因此到任务运行变量i已经到达了循环的结尾。

To fix this you need to take a copy of i inside the loop and use that. 要解决此问题,您需要在循环内复制i并使用它。

Try this code: 试试这个代码:

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());
}

Now, in preference I'd use Microsoft's Reactive Framework (NuGet "System.Reactive") to do this work. 现在,我将优先使用Microsoft的Reactive Framework(NuGet“ System.Reactive”)来完成这项工作。 Your code would look like this: 您的代码如下所示:

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));
}

Done. 做完了 That's it. 而已。

When I run my code (with the AssignTask outputting to the Console) I get this: 当我运行代码(将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

The .ObserveOn(listBoxToDo) works for Windows Forms to marshall back to the UI thread. .ObserveOn(listBoxToDo)适用于Windows窗体,以编组回UI线程。

You are using variable "i" from the loop inside the task. 您正在任务内部的循环中使用变量“ i”。 "i" might have changed while your task started. 您的任务开始时“ i”可能已更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM