【问题标题】:Most Appropriate Use Of Async/Await When Not Returning The Task Directly?不直接返回任务时最合适使用Async/Await?
【发布时间】:2017-08-18 06:28:45
【问题描述】:

我在我的代码中经常使用 async await,但我突然想到我可能没有按照我应该做的那样适当地使用它。

我正在寻找确认我对处理异步/等待的最佳方法的理解,这些方法执行多项操作并且不直接返回任务结果。

当我只想直接返回任务结果时,我通常会这样做。

    //basic - 1 thing to do - directly return task
    public Task<string> ReturningATask(string key)
    {
        return _cache.GetStringAsync(key);
    }

但是,当我想在返回之前一些与任务的值相关的事情时,我习惯于只异步方法并等待其中的任务。

    //More than a single operation going on.
    //In this case I want to just return a bool indicating whether or not the key exists.
    public async Task<bool> ReturningABool(string key)
    {
        string foundValue = await _cache.GetStringAsync(key);

        if (string.IsNullOrEmpty(foundValue))
        {
            return false;
        }
        else
        {
            return true;
        }
    }

在我看来,ContinueWith 可能是更合适的处理方式。

以下示例是普遍接受的处理方式吗? 我进入了我的脑海“永远不要使用 task.Result,因为它正在阻塞”,但是使用 ContinueWith,任务已经完成,所以没有阻塞吧?

    //The more correct way?        
    public Task<bool> ReturningATaskBool(string key)
    {
        return _cache.GetStringAsync(key)
            .ContinueWith(x =>
            {
                if (string.IsNullOrEmpty(x.Result))
                {
                    return false;
                }
                else
                {
                    return true;
                }
            });
    }

谢谢。

【问题讨论】:

  • 用异步/等待返回任务。
  • 是的,对不起,你说的很对,我说错了。我想我搞砸了我的第二个代码示例,因为我通常所做的只是将其设为 async bool,而不是 async Task 当然不会返回任务。编辑问题以删除该位。
  • 你可以做return !string.IsNullOrEmpty(x.Result)

标签: c# asynchronous async-await task-parallel-library


【解决方案1】:

大多数时候它并没有太大的区别。 async/await 的开销可能比ContinueWith 略高(尽管它确实取决于场景),但我怀疑这是你应该担心的事情。选择你觉得更容易阅读的那个。

您唯一应该注意的是await 会将延续发布到当前同步上下文(如果有)。如果您在 winform/wpf 应用程序中,这可能特别有用。另一方面,ContinueWith 在当前任务调度程序(通常是线程池)上执行延续。

我在脑海中“永远不要使用 task.Result,因为它正在阻塞”,但是使用 ContinueWith,任务已经完成,所以没有阻塞吧?

没错,您使用ContinueWith 的方式很好。

【讨论】:

    【解决方案2】:

    ContinueWith 是一个危险的低级 API。具体来说:

    • 不理解异步延续。
    • 使用当前TaskScheduler(不是默认TaskScheduler)作为其TaskScheduler参数的默认值。
    • 没有适当的延续标志的默认行为(例如,DenyChildAttach)。

    await 没有这些问题。您应该使用await 而不是ContinueWith

    See my blog for an exhaustive (exhausting?) discussion.

    【讨论】:

    • 嗯,我担心 ContinueWith 可能存在一些“陷阱”,例如异常处理。我会坚持我习惯的等待。
    • @Steviebob ContinueWith 在 Async-Await 被引入之前就已经存在,并被用于异步实现作为一种解决方法,它是非阻塞的,并且比 APM 简单得多。现在发布异步等待的介绍,没有更好的选择。
    猜你喜欢
    • 2020-09-21
    • 1970-01-01
    • 1970-01-01
    • 2012-05-07
    • 1970-01-01
    • 2017-04-21
    • 2018-06-24
    • 1970-01-01
    • 2019-06-26
    相关资源
    最近更新 更多