【问题标题】:Multiple Task.Run vs no await for async method? [duplicate]多个 Task.Run 与不等待异步方法? [复制]
【发布时间】:2019-11-28 03:29:56
【问题描述】:

我有一些 IO-Bound 作业(定期将一些数据写入文件)代码如下:

public async Task SaveToFile1(int sleepTimeout)
{
     while (true)
     {
        // Do file saving work
        await Task.Delay(sleepTimeout).ConfigureAwait(false);
     }
}

public async Task SaveToFile2(int sleepTimeout)
{
    while (true)
    {
        // Do file saving work
        await Task.Delay(sleepTimeout).ConfigureAwait(false);
    }
}

public async Task SaveToFile3(int sleepTimeout)
{
    while (true)
    {
        // Do file saving work
        await Task.Delay(sleepTimeout).ConfigureAwait(false);
    }
}

调用者是主要方法。 当我使用以下两种方式运行它们时,这些任务运行良好并产生了正确的结果:

void main () 
{
    // other codes

    // way 1:
    SaveToFile1(1000);
    SaveToFile2(1000);
    SaveToFile3(1000);

    // other codes will not let the app exit
}
void main () 
{
    // other codes

    // way 2:
    Task.Run(async() => await SaveToFile1(1000));
    Task.Run(async() => await SaveToFile2(1000));
    Task.Run(async() => await SaveToFile3(1000));

    // other codes will not let the app exit
}

哪种方法对我来说是最好的选择?

感谢您的回答!


编辑:

在方式1中,当await Task.Delay'完成'时,可能会捕获一个新的线程池线程来执行循环的下一步,...,循环将始终在await命中的其他线程中运行。

在方式2中,当Task.Run立即执行时,可能会使用一个新的线程池线程,循环总是在开始时在其他线程中运行。

结果都一样,区别在哪里?

所以我的问题不在于 Task.Run 与 async-await!

【问题讨论】:

  • 正确的方法 non
  • 那是“I/O 代码”?对我来说好像睡了很多觉
  • @Selvin 请添加 Console.ReadKey();在 main 的最后,我在真实环境中有一些块代码。由于 dotnetfiddle 不支持循环代码,因此您应该使用真正的控制台应用程序。
  • @MickyD 在下次睡眠之前有一些 IO 代码。
  • “结果是一样的,区别在哪里?” -- 你自己已经发现了区别:使用Task.Run() 会导致你的@ 初始执行987654329@ 方法发生在线程池线程而不是当前线程中。这可能很重要,也可能不重要,具体取决于初始代码需要多长时间。标记的重复项也有解释这种确切差异的答案。它是唯一的材料,IMO。如果不是这样,我会说永远不要将Task.Run() 与异步方法一起使用。许多(如果不是大多数)异步方法旨在尽快到达第一个等待。

标签: c# asynchronous task


【解决方案1】:

异步代码允许在等待来自其他事物的响应时释放当前线程来做其他工作。但是第一个 await 之前的所有代码都将在您调用它的同一线程上完成。如果该代码占用大量 CPU 资源,则可能会引起注意。

如果您不使用Task.Run,该方法将在同一个线程上运行,直到第一个异步 I/O 请求,当它返回一个 Task 并且您的下一个方法将被调用。

Task.Run 将在不同的线程上执行代码。如果它确实执行了一些 CPU 繁重的工作并且您不希望在当前线程上完成(例如在桌面应用程序中您不希望在 UI 线程上完成),那么这很好。但是启动一个新线程也有一点成本。

使用Task.Run 是否会产生明显的差异取决于您正在编写的应用类型以及您的方法的作用。

如果你不立即等待它们很好,但如果你不等待它们,那么你将永远不知道它们何时完成,它们是否成功完成,或者抛出异常。这被称为“一劳永逸”。仅当您不在乎他们是否成功时才这样做。

相反,您可以在最后等待以确保它们成功完成。例如:

void main () 
{
    // other codes

    var taskList = new List<Task>();
    taskList.Add(SaveToFile1(1000));
    taskList.Add(SaveToFile2(1000));
    taskList.Add(SaveToFile3(1000));

    // other codes will not let the app exit

    // wait till everything finishes before exiting
    await Task.WhenAll(taskList);
}

【讨论】:

  • 因为有循环,所以任务可能一直在运行,最后的await有影响吗?
  • 不,我猜不是 :) 如果他们从不退出循环,则不会。
猜你喜欢
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
  • 2015-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多