什么是包同步code作为一种异步任务的最佳方法是什么?任务、方法、code

2023-09-05 23:46:33 作者:夏至

我实现一个接口方法是异步的(返回的任务)。然而,我的实现是必然同步。什么是做到这一点的最好方法是什么?有一些内置的方式做到这一点?这里有几个选项,我在考虑:

I am implementing an interface method that is asynchronous (returns Task). However, my implementation is by necessity synchronous. What's the best way to do this? Is there some built-in way to do this? Here are several options I'm considering:

选项1:Task.FromResult

Option 1: Task.FromResult

return Task.FromResult(ComputeResult());

这是一件好事,因为我的code同步运行。其缺点是,如果ComputeResult()失败或取消我的方法抛出,而不是返回一个失败的任务。

This is good because my code runs synchronously. The disadvantage is that if ComputeResult() fails or is canceled my method throws instead of returning a failed task.

选项2:Task.Run

Option 2: Task.Run

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

这更自然传播失败和取消。然而,这也会引入不必要的螺纹跳

This propagates failure and cancellation more naturally. However, this also introduces an unnecessary thread-hop.

选项3:TaskCompletionSource Git在实际工作中的使用方法

Option 3: TaskCompletionSource

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

return tcs.Task;

这两种传播失败/取消和避免线程跳,但它是更冗长和复杂的。

This both propagates failure/cancellation AND avoids the thread-hop, but it's more verbose and complex.

推荐答案

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

Two other options you might have overlooked:

只是让你的方法异步返回ComputeResult()。燮preSS与编译器警告。如果你不喜欢晚饭preSS的警告,你可以这样做:

just make your method async and do return ComputeResult(). Suppress the compiler warning with pragma. If you don't like to suppress the warning, you could do this:

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

,后者会提供类似于异步方法异常传播。但是请注意,在一定条件下(比如当这是太深堆栈上), RunSynchronously 仍然可以异步执行。

The latter will provide exception propagation similar to the async method. Note however, under certain conditions (like when it's too deep on the stack), RunSynchronously could still execute asynchronously.