What is the best way to wrap synchronous code as an async task?

I am implementing an interface method that is asynchronous (returns a task). However, my implementation is synchronous as needed. What is the best way to do this? Is there a built-in way to do this? Here are a few options that I am considering:

  • Option 1: Task.FromResult

    return Task.FromResult(ComputeResult()); 

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

  • Option 2: Task.Run

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

This more naturally applies to rejection and cancellation. However, this also introduces an unnecessary stream-hop.

  • 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 extends as a denial / cancellation AND excludes the stream-hop, but it is more detailed and complex.

+3
source share
1 answer

Two other options you might have missed:

  • just make your async method and do return ComputeResult() . Suppress compiler warning with pragma . If you do not want to suppress the warning, you can do this:

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

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

The latter will provide exception propagation similar to the async method. However, note that under certain conditions (for example, when it is too deep on the stack), RunSynchronously can still execute asynchronously.

+2
source

Source: https://habr.com/ru/post/989155/


All Articles