Wrapping a non-async method (which makes web calls) in async

I know that you should use async only for materials that are not "CPU intensive", for example. file recordings, web calls, etc., so I also know that it makes no sense to wrap each method in Task.Run or something like that.

However, what should I do when I know that the method makes a web call, but it does not offer an asynchronous interface. In this case, is it worth wrapping it?

Specific example:

I am using CSOM (the SharePoint client object model) in my WebApi application (server) and want to get a list of SharePoint.

This is usually done as follows:

 [HttpGet] [Route("foo/{webUrl}")] public int GetNumberOfLists(string webUrl) { using (ClientContext context = new ClientContext(webUrl)) { Web web = context.Web; context.Load(web.Lists); context.ExecuteQuery(); return web.Lists.Count; } } 

And I thought about changing it to something like this:

 [HttpGet] [Route("foo/{webUrl}")] public async Task<int> GetNumberOfLists(string webUrl) { using (ClientContext context = new ClientContext(webUrl)) { Web web = context.Web; context.Load(web.Lists); await Task.Run(() => clientContext.ExecuteQuery()); return web.Lists.Count; } } 

Does it make sense and does it help? As far as I understand, I just create / need a new thread to execute the request ("overhead"), but at least the request stream will be free / ready for another request (that would be good).

But is it worth it, and should it be done so?

If yes: Is it not strange that Microsoft does not offer an “asynchronous” method out of the box, or do they just not care about it?

edit: updated to use Task.Run as indicated in the comment.

+5
source share
2 answers

However, what should I do when I know that the method makes a web call, but it does not offer an asynchronous interface.

Unfortunately, it is still quite common. As different libraries update their APIs, they will ultimately catch up.

In this case, is it worth wrapping it?

Yes, if you are dealing with a UI thread. Otherwise, no.

Case study ... in a WebApi application (server)

Then no, you do not want to embed Task.Run . As noted in an article on async ASP.NET :

You can run some background work while waiting for Task.Run, but that doesn't make sense. In fact, it will actually hurt your scalability by interfering with the ASP.NET thread pool heuristic ... As a rule, the thread pool queue on ASP.NET does not work.

Wrapping using Task.Run on ASP.NET:

  • Interacts with ASP.NET thread pool heuristics twice (by taking a thread and then freeing it later).
  • Adds overhead (code should switch threads).
  • Does not free the thread (the total number of threads used for this request is almost equal to just invoking the synchronous version).

As I understand it, I just create / need a new thread to execute the request ("overhead"), but at least the request stream will be free / ready for another request (that would be good).

Yes, but all you do is jump streams without any benefit. The thread used to block the result of a request is one thread that ASP.NET should use to process requests, so freeing up one thread by consuming another is not a good compromise.

Is it not strange that Microsoft does not offer the “asynchronous” method out of the box, or just do not need it?

Some of the "old" MS APIs simply did not go as far as adding async versions. They certainly should, but development time is the ultimate resource.

+4
source

This is my personal view of your problem, and for me the above path is not required. When we host your API in IIS, the server assigns one thread from the thread pool that it has on the server. IIS also has the parameter maxConcurrentRequestsPerCPU maxConcurrentThreadsPerCPU. You can configure these values ​​to serve the request, instead of processing the request yourself.

0
source

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


All Articles