首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Task.Run是否产生I/O绑定操作的开销?

Task.Run是否产生I/O绑定操作的开销?
EN

Stack Overflow用户
提问于 2020-01-14 20:37:12
回答 3查看 583关注 0票数 2

我想通过HttpClient以异步方式从各种服务下载数据(出于测试目的,我用Task.Delay创建了几个方法)。因此,首先,我决定创建任务列表,并最终使用await Task.WhenAll(tasks)等待一切。

一切都是我想要的,但是如果我把lambda传递给tasks.Add(),就会有一个问题。我必须使用Task.Run,因为没有它就不能使用,等待内部。

所以我的问题是:

这个Task.Run()会产生额外的开销吗?因为对于I/O绑定操作,我们不应该使用Task.Run,而应该使用简单的异步等待。

代码语言:javascript
运行
复制
class Program
{
    public static async Task<int> DownloadDelay15()
    { await Task.Delay(15000); return 15; }

    public static async Task<int> DownloadDelay2()
    { await Task.Delay(1000); return 2; }

    static async Task Main(string[] args)
    {
        var tasks = new List<Task<int>>();
        tasks.Add(DownloadDelay15());
        tasks.Add(DownloadDelay2());
        tasks.Add(Task.Run(async () => //additional overhead?
        {
            await Task.Delay(1000);
            return 6;
        }));

        var watch = Stopwatch.StartNew();
        var results = await Task.WhenAll(tasks);
        watch.Stop();
        var elapsedSeconds = watch.Elapsed.Seconds;
    }  
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-01-14 21:14:53

如果我将lambda传递给tasks.Add(),则为tasks.Add()。我必须使用Task.Run,因为没有它就不能使用,等待内部。

不能将lambda传递给Add;需要将Task传递给Add。您可以通过创建另一个方法来做到这一点:

代码语言:javascript
运行
复制
async Task<int> DownloadDelay6()
{
  await Task.Delay(1000);
  return 6;
}

var tasks = new List<Task<int>>();
tasks.Add(DownloadDelay15());
tasks.Add(DownloadDelay2());
tasks.Add(DownloadDelay6());

这个Task.Run()会产生附加开销吗?因为对于IO绑定操作,我们不应该使用Task.Run,而应该使用简单的异步等待。

是的;Task.Run在线程池线程上运行它的委托,因此有一些额外的开销。它不是很多,但它在那里。

票数 6
EN

Stack Overflow用户

发布于 2020-01-14 22:25:57

如果您想要将lambda传递给您的列表,我建议您将其设置为委托列表,而不是任务列表。然后,您可以将其转换为任务列表,以便等待它。

代码语言:javascript
运行
复制
static async Task Main(string[] args)
{
    var jobs = new List<Func<Task<int>>>
    {
        DownloadDelay15,
        DownloadDelay2,
        async () => { await Task.Delay(1000); return 6; }
    };

    var tasks = jobs.Select(job => job()).ToList();

    var watch = Stopwatch.StartNew();
    var results = await Task.WhenAll(tasks);
    watch.Stop();
    var elapsedSeconds = watch.Elapsed.Seconds;
}

为了回答您的问题,是的,Task.Run会造成一些开销,因为以这种方式执行的任务会放在线程池上。

票数 2
EN

Stack Overflow用户

发布于 2020-01-14 22:23:20

如果你用Task.Run..。

  1. 将会有额外的开销。
  2. 您的程序可能会运行得更快。

这听起来可能自相矛盾。假设您将在一台多核计算机上运行,您的程序将运行得更快的原因是任务将并行启动。如果您的任务可以启动,CPU要求为零,并且您的示例中的任务就是这样,则这可能与此无关,但并非所有任务都可以立即启动。有些任务包括在任务启动之前运行的同步代码。如果没有Task.Run,这个同步代码将按顺序运行,因为一个任务将一个接一个地启动。使用Task.Run,同步代码将在所有可用内核中并行运行。Task.Run的额外开销将由整个系统支付,而不仅仅由您的程序支付。开销很小,每次调用大约有2微秒的CPU时间,所以很可能您也不会注意到任何不同,除非您一次运行数十万个任务。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59741440

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档