将同步代码包装为异步任务的最佳方法是什么?

时间:2015-06-15 18:01:40

标签: c# .net async-await task

我正在实现异步的接口方法(返回Task)。但是,我的实现必然是同步的。最好的方法是什么?有没有一些内置的方法来做到这一点?以下是我考虑的几个选项:

  • 选项1:Task.FromResult

    return Task.FromResult(ComputeResult());
    

这很好,因为我的代码同步运行。缺点是如果ComputeResult()失败或被取消,我的方法抛出而不是返回失败的任务。

  • 选项2:Task.Run

    return Task.Run(() => ComputeResult());
    

这更自然地传播失败和取消。但是,这也引入了不必要的线程跳。

  • 选项3:TaskCompletionSource

    var tcs = new TaskCompletionSource<T>();
    try 
    { 
        tcs.SetResult(ComputeResult()); 
    }
    catch (OperationCanceledException) 
    { 
        tcs.SetCanceled(); 
    }
    catch (Exception ex) 
    { 
        tcs.SetException(ex); 
    }
    
    return tcs.Task;
    

这会传播失败/取消并避免线程跳跃,但它更冗长和复杂。

1 个答案:

答案 0 :(得分:2)

您可能忽略了另外两个选项:

  • 只需制作您的方法async并执行return ComputeResult()即可。使用pragma抑制编译器警告。如果你不想取消警告,你可以这样做:

    async Task<Result> ComputeResultAsync()
    {
        await Task.FromResult(0);
        return ComputeResult();
    }
    
  • 使用Task.RunSynchronously

    Task<Result> ComputeResultAsync()
    {
        var task = new Task<Result>(() => ComputeResult());
        task.RunSynchronously(TaskScheduler.Default);
        return task;
    }
    

后者将提供类似于async方法的异常传播。但请注意,under certain conditions(就像它在堆栈上太深时),RunSynchronously仍然可以异步执行。