【问题标题】:When is using Task.Run wasteful or delusional?什么时候使用 Task.Run 是浪费或妄想?
【发布时间】:2015-01-14 14:01:31
【问题描述】:

我有一个将对象读/写到存储的接口。在一种情况下,存储是具有异步方法的数据库。在另一种情况下,它只是一个 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);
    });
}

【问题讨论】:

  • 那么,您能够注意到您的代码占用 TP 线程 30 纳秒的确切几率是多少? Cookie 通常适用于延迟比其多 百万 倍的网络连接。
  • @James 我认为您不能在接口方法上使用async 修饰符。
  • 看看my async-await curation上的文章。

标签: c# asynchronous async-await


【解决方案1】:

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

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

【讨论】:

  • 这改变了异常处理语义,使得异常不会被包装在返回的任务中。
  • @Servy 任务返回方法同步抛出异常的情况并不少见。以Task.Delay 为例...
  • @I3arnon 我并没有说这是错误的,只是他正在改变语义。如果用户想要那些改变的语义,那是他们的决定。
【解决方案2】:

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

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

【讨论】:

  • 然后你会得到一个编译器警告。
  • @SLaks 是的,你会的。但既然你知道你的代码是正确的,你可以放心地忽略它。
  • @SLaks 不仅仅是编译器警告,它还包含async 方法的全部开销,包括构建此处不需要的状态机。
  • @I3arnon 它在编译时增加了一些工作;但考虑到它实际上并没有等待开销,纯粹是创建一个对象实例;这根本不是很贵。
【解决方案3】:

几乎就像 SLaks 建议的那样,如果您正在执行异步操作但返回任务,那么:

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);
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-09
    • 1970-01-01
    • 2010-10-19
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    相关资源
    最近更新 更多