.NET异步任务需要太长时间才能创建[关闭]

问题描述 投票:-2回答:2

是否有理由让async Task<> foo()花时间创作? (刚刚创建,等待它需要另外一段时间)。在分析我的Web服务性能时,我注意到仅仅创建任务需要相当长的时间(大约几百毫秒)。

//DB intensive async tasks, just creating them all takes 600ms-1800ms
Task<Egg> eggTask = FryEggs(2);
Task<Bacon> baconTask = FryBacon(3);
Task<Toast> toastTask = ToastBread(2);
//actually awaiting them takes some hundreds of milliseconds more...
await Task.WhenAll(eggTask, baconTask, toastTask);

有问题的函数在第一次等待它们之前不会做大量的同步工作,所以我找不到令人信服的理由让它们以这种方式工作。这种方式的东西:

async Task<Object> FryEggs(){
    VeryLightweightSynchronousWork();
    await BottleneckingIOWork();
}

我尝试过使用Task.Factory.StartNew并立即返回:

async Task<Object> FryEggs(){
    var res = await Task.Factory.StartNew(async => {
        VeryLightweightSynchronousWork();
        return await BottleneckingIOWork();
    }
    return await res;
}

我不明白这种行为。

我实际上并不太关心我的具体情况,我想理解为什么,在基于参考的观点上,这应该发生。我目前的理解是,一旦Task被调用就会启动,但它应该异步执行。那么,为什么主线程会等待创建异步任务呢?

先感谢您!

c# asynchronous async-await task
2个回答
1
投票

只需创建它们需要600ms-1800ms

最有可能的是,你的数据库密集型工作正在同步完成一些工作;或许打开连接,也许发出命令 - 我们不可能知道。如果您向我们展示了FryEggs的确切功能,并告诉我们您正在使用哪个ADO.NET提供商,我们可能会进一步提供建议。请注意,某些ADO.NET提供程序对其*Async实现使用async-over-sync,这意味着它们实际上只是同步。因此,确切的ADO.NET提供程序和版本非常重要。


0
投票

当异步方法返回一个Task时,它用于继续该方法。该方法的开头仍然立即执行。

async Task FryEggs(int count)
{
    //Anything here will cause FryEggs to block the caller until it is completed

    await DoSomethingAsync();

    //Anything down here is the "continuation" which will execute after the task is returned
}

如果您希望立即返回不完整的任务,可以在最开始添加等待,例如使用Task.Yield

async Task FryEggs(int count)
{
    await Task.Yield();

    //Now this is part of the continuation too. It won't run until after the Task is returned.

    await DoSomethingAsync();
}

我不确定这对你的场景来说是最好的想法,但它是一个选择。

如果FryEggs包含CPU绑定的工作,并且您希望通过并行性来改进,则可能需要在单独的线程上运行它:

async Task FryEggs(int count)
{
    await Task.Run( () =>
    {
        //Do something super-expensive and synchronous
    });
    await DoSomethingAsync();
}

这样一开始就有一个等待,所以控制权会立即回归。昂贵的东西放在线程池中自己的线程上。逻辑可以通过closures访问相同的局部变量;只要你等待Task.Run()电话,这是安全的。

async Task FryEggs(int count)
{
    string[] results; //This local variable will be closed over

    await Task.Run( () =>
    {
        //Do something super-expensive and synchronous
        results = GetResults();
    });
    await DoSomethingAsync(results);
}
© www.soinside.com 2019 - 2024. All rights reserved.