什么时候使用 Task.Run 是浪费或妄想?

When is using Task.Run wasteful or delusional?

我有一个接口,reads/writes 存储一个对象。在一种情况下,存储是具有异步方法的数据库。在另一种情况下,它只是一个 cookie。

我收集到它建议沿着以异步调用结束的路径使用异步返回,因此接口也是异步的似乎也有意义。但在 cookie 的情况下,我只是设置了几个字段并将其粘贴在响应中,因此那里还没有任何异步。我可以将该位包装在 await Task.Run() 中以匹配新界面,但我不知道这是否可取,或者它是否会对性能产生一些负面影响。

怎么办?

public interface IProfileStore
{
    async Task SetProfile(UserProfile profile);
}

public async Task SetProfile(UserProfile profile)
{
    // Look mom, I'm needlessly async
    await Task.Run(() =>
    {
        var cookie = new HttpCookie(AnonymousCookieName);
        cookie["name"] = profile.FullName;
        HttpContext.Current.Response.Cookies.Add(cookie);
    });
}

如果您正在执行一个非常短的快速完成的操作,那么您可能不需要使用 Task.Run 将工作推送到另一个线程,这是非常正确的。在线程池中调度代码的行为可能比 只是这样做 .

花费更长的时间

至于如何做到这一点,只需删除您不需要的 await Task.Run,瞧,一切就绪。您有一个同步操作仍然包装在 Task 中,因此仍然匹配所需的接口。

你不应该那样做;你只是在创建不必要的线程池流失。

相反,从方法中删除 async 关键字并简单地 return Task.FromResult(0) 到 return 一个同步完成的任务

几乎如 SLaks 所建议的那样,如果你正在做一些异步的事情,但 return 任务,那么:

public Task SetProfile(UserProfile profile)
{
    return Task.Run(() =>
    {
        var cookie = new HttpCookie(AnonymousCookieName);
        cookie["name"] = profile.FullName;
        HttpContext.Current.Response.Cookies.Add(cookie);
    });
}

然而,正如他在这种情况下所建议的那样:

public Task SetProfile(UserProfile profile)
{
    var cookie = new HttpCookie(AnonymousCookieName);
    cookie["name"] = profile.FullName;
    HttpContext.Current.Response.Cookies.Add(cookie);
    return Task.FromResult(null);
}

Return null 作为系统缓存的已完成任务。