The task. Run or not run the task.

Suppose I have an interface that includes the async method, and I have two different implementations of this interface. One of the two implementations is naturally asynchronous, while the other is not. What would be the “most correct” way to implement a non-asynchronous method?

public interface ISomething { Task<Foo> DoSomethingAsync(); } // Normal async implementation public class Implementation1 : ISomething { async Task<Foo> ISomething.DoSomethingAsync() { return await DoSomethingElseAsync(); } } // Non-async implementation public class Implementation2 : ISomething { // Should it be: async Task<Foo> ISomething.DoSomethingAsync() { return await Task.Run(() => DoSomethingElse()); } // Or: async Task<Foo> ISomething.DoSomethingAsync() { return DoSomethingElse(); } } 

I try to keep up with the Steven Cleary blog , and I do not know that none of them gives any advantages async, and I'm fine. The second seems to me more correct, since it does not pretend that it is not, but it gives a warning about the compiler, and they add up and are distracted.

All this will be inside ASP.NET (both web MVC and WebAPI), if that matters.

+6
source share
2 answers

You can abandon the async modifier and use Task.FromResult to return the completed task synchronously:

 Task<Foo> ISomething.DoSomethingAsync() { return Task.FromResult(DoSomethingElse()); } 

This takes care of this warning and has better performance since it does not require the async state utility.

However, this will slightly change the semantics of exception handling. If this is a problem, you should use the async method synchronous approach and accept the warning (or disable it with a comment):

 #pragma warning disable 1998 async Task<Foo> ISomething.DoSomethingAsync() #pragma warning restore 1998 { return DoSomethingElse(); } 

As Stephen Cleary said, you can also take care of this warning (keeping the synchronous method) while waiting for the task already completed:

 async Task<Foo> ISomething.DoSomethingAsync() { await Task.FromResult(false); // or Task.CompletedTask in .Net 4.6 return DoSomethingElse(); } 
+8
source

It really depends on what your method does:

  • no input / output, negligible amount of processor work.
  • cpu intensive work
  • intensive I / O

no I / O, negligible amount of processor work

You must calculate the result synchronously and create a task containing the result.

 Task<Foo> ISomething.DoSomethingAsync() { Foo result; // do something not hurting performance // no I/O here return Task.FromResult(result); } 

Note that when the method is called, any exception will be thrown, and not when the task is waiting. For the latter case, which corresponds to other types of work, you should use async, however:

 async Task<Foo> ISomething.DoSomethingAsync() { Foo result; // do something not hurting performance // no I/O here return result; } 

cpu intensive work

You must run the task with Task.Run and do the intensive work of the processor in the task.

 Task<Foo> ISomething.DoSomethingAsync() { return Task.Run(() => { Foo result; // do some CPU intensive work here return result; }); } 

intensive I / O

You must use the async and wait for some async input / output method. Do not use synchronous I / O methods.

 async Task<Foo> ISomething.DoSomethingAsync() { Stream s = new .... // or any other async I/O operation var data = await s.ReadToEndAsync(); return new Foo(data); } 
+2
source

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


All Articles