【问题标题】:Task.Start strange behaviorTask.Start 奇怪的行为
【发布时间】:2021-03-17 21:49:09
【问题描述】:

您好,我有以下创建任务的代码。然后将其设置为启动。 该任务旨在向ConcurrentBag 列表添加响应。 但是 await 似乎并没有等待所有任务完成。但它们被标记为已完成。列表中只有一项任务。 使用Task.Run时效果很好!

public async void RunT1()
{          
    DoesNotWork();
}

public async void RunT2()
{          
    DoesWork();
}

public async void DoesNotWork()
{
    ConcurrentBag<string> concurrentBag = new ConcurrentBag<string>();
    List<Task> taskList = new List<Task>();

    Task task1 = new Task(async () =>
    {
        var xml = await LongWorkingMethod();
        concurrentBag.Add(xml);
    });

    taskList.Add(task1);

    taskList[0].Start();
    await Task.WhenAll(taskList);

    if (concurrentBag.Count > 0) //concurrentBag is empty,
        //even though the task has finished
    {
        Debug.Print("success");
    }
}

public async void DoesWork()
{
    ConcurrentBag<string> concurrentBag = new ConcurrentBag<string>();
    List<Task> taskList = new List<Task>();

    Task task1 = Task.Run(async () =>
    {
        var xml = await LongWorkingMethod();
        concurrentBag.Add(xml);
    });

    taskList.Add(task1);

    await Task.WhenAll(taskList);

    if (concurrentBag.Count > 0) //concurrentBag is NOT empty
    {
        Debug.Print("success");
    }
}

【问题讨论】:

    标签: c# .net task-parallel-library async-await


    【解决方案1】:

    几乎没有理由直接使用Task 构造函数。

    在您的情况下,Task 构造函数不支持async 委托(即Action 而不是Func&lt;Task&gt;),当您将一个作为参数传递时,它被视为async void。

    这意味着调用Start “触发并忘记”委托并且它不能等待其中的异步操作完成,因为没有Task到await。

    var task = new Task(async () => await Task.Delay(1000));
    task.Start();
    await task; // completes immediately
    

    如果您需要运行新的Task,请使用Task.Run。如您所见,Task.Run 确实支持 async 委托并等待整个操作完成

    var task = Task.Run(async () => await Task.Delay(1000));
    await task; // completes after 1000 milliseconds
    

    【讨论】:

    • 我想在以后一次运行 2 个。是的,这是有道理的。但似乎没有一个选项来处理我的 taskList 说只使用 2 个线程。如果我使用 Task.Run 将它们添加到列表中,它将用完所有线程
    • @lymber 如果您想先准备它们并稍后执行它们,我会简单地存储Func&lt;Task&gt; 的列表,当您调用它们时它们开始运行。
    • 是的,但我不希望它们都开始运行。只需同时运行两个,等待这两个运行,然后执行接下来的两个,直到列表被消耗。
    • @lymber 然后只调用其中的 2 个 lambda,await 返回的任务,并调用接下来的 2 个。另外,您应该看看 TPL Dataflow 的 ActionBlock
    猜你喜欢
    • 2019-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    • 2015-07-20
    • 2010-10-03
    • 2021-07-12
    • 2013-10-04
    相关资源
    最近更新 更多