包装同步code到异步调用 [英] Wrapping synchronous code into asynchronous call

查看:155
本文介绍了包装同步code到异步调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在ASP.NET应用程序的方法,消耗相当多的时间才能完成。对此方法的调用可能一个用户请求期间,出现高达3倍根据缓存状态,并且用户提供的参数。每次通话时间约1-2秒即可完成。该方法本身是同步调用服务,并且没有可能覆盖的执行。结果,
因此,对服务的同步调用看起来像下面这样:

I have a method in ASP.NET application, that consumes quite a lot of time to complete. A call to this method might occur up to 3 times during one user request, depending on the cache state and parameters that user provides. Each call takes about 1-2 seconds to complete. The method itself is synchronous call to the service and there is no possibility to override the implementation.
So the synchronous call to the service looks something like the following:

public OutputModel Calculate(InputModel input)
{
    // do some stuff
    return Service.LongRunningCall(input);
}

和方法的使用是(注意,方法的该呼叫可能会发生一次以上):

And the usage of the method is (note, that call of method may happen more than once):

private void MakeRequest()
{
    // a lot of other stuff: preparing requests, sending/processing other requests, etc.
    var myOutput = Calculate(myInput);
    // stuff again
}

我试图实施从我身边改变提供这种方法同时工作,这里就是我来这么远。<​​/ P>

I tried to change the implementation from my side to provide simultaneous work of this method, and here is what I came to so far.

public async Task<OutputModel> CalculateAsync(InputModel input)
{
    return await Task.Run(() =>
    {
        return Calculate(input);
    });
}

用法(的做其他的东西code部分与呼叫服务同时运行):

Usage (part of "do other stuff" code runs simultaneously with the call to service):

private async Task MakeRequest()
{
    // do some stuff
    var task = CalculateAsync(myInput);
    // do other stuff
    var myOutput = await task;
    // some more stuff
}

我的问题如下。我用正确的方法来加快在ASP.NET应用程序中执行或我在做不必要的工作努力异步运行同步code?任何人都可以解释为什么第二个方法是不是在ASP.NET一个选项(如果它是真的不)?另外,如果这样的方法是适用的,我需要异步调用该方法,如果它是我们可能会在此刻(我有这样的情况下,如果没有其他的东西存在,而等待完成办)进行的来电?

大多数关于这一主题在网的文章中介绍了使用异步等待与code,已经提供的方法 awaitable 方法,但这不是我的情况。 这里是说明我的情况,这不介绍好文章并行调用的情况,下降的选项包同步调用,但在我看来我的情况完全场合这样做。结果
先谢谢您的帮助和提示。

My question is the following. Do I use the right approach to speed up the execution in ASP.NET application or am I doing unnecessary job trying to run synchronous code asynchronously? Can anyone explain why the second approach is not an option in ASP.NET (if it is really not)? Also, if such approach is applicable, do I need to call such method asynchronously if it is the only call we might perform at the moment (I have such case, when no other stuff there is to do while waiting for completion)?
Most of the articles in the net on this topic covers using async-await approach with the code, that already provides awaitable methods, but that's not my case. Here is the nice article describing my case, which doesn't describe the situation of parallel calls, declining the option to wrap sync call, but in my opinion my situation is exactly the occasion to do it.
Thanks in advance for help and tips.

推荐答案

,使两种不同类型的并发之间的区别是很重要的。的异步的并发当你有多个航班异步操作(和因为每个操作是异步的,他们都不是实际使用的线程的)。 平行的并发性是当你有每做一个单独操作多个线程。

It's important to make a distinction between two different types of concurrency. Asynchronous concurrency is when you have multiple asynchronous operations in flight (and since each operation is asynchronous, none of them are actually using a thread). Parallel concurrency is when you have multiple threads each doing a separate operation.

做的第一件事是重新评估这一假设:

The first thing to do is re-evaluate this assumption:

的方法本身是对服务同步调用,并且没有可能覆盖的实施

The method itself is synchronous call to the service and there is no possibility to override the implementation.

如果你的服务是的网站的服务或其他任何东西,是I / O密集​​型,那么最好的解决办法是写一个异步API吧。

If your "service" is a web service or anything else that is I/O-bound, then the best solution is to write an asynchronous API for it.

我会假设你的服务是CPU密集型的操作,必须在同一台机器上执行与Web服务器进行。

I'll proceed with the assumption that your "service" is a CPU-bound operation that must execute on the same machine as the web server.

如果是这样的话,那么,以评估接下来的事情就是另外一个假设:

If that's the case, then the next thing to evaluate is another assumption:

我需要更快地执行请求。

I need the request to execute faster.

您绝对肯定这就是你需要做什么?是否有任何前端更改,可以代替 - 例如,启动该请求,并允许用户做其他工作,而它的处理

Are you absolutely sure that's what you need to do? Are there any front-end changes you can make instead - e.g., start the request and allow the user to do other work while it's processing?

我也有同感,是的,你确实需要进行单独的请求执行速度更快的假设进行。

I'll proceed with the assumption that yes, you really do need to make the individual request execute faster.

在这种情况下,你需要在Web服务器上并行执行code。这绝对不是一般的建议,因为并行code将使用ASP.NET可能需要处理其他请求的线程,并通过删除/添加线程就会抛出了ASP.NET线程池启发式关闭。所以,这个决定确实有你的整个服务器上的影响。

In this case, you'll need to execute parallel code on your web server. This is most definitely not recommended in general because the parallel code will be using threads that ASP.NET may need to handle other requests, and by removing/adding threads it will throw the ASP.NET threadpool heuristics off. So, this decision does have an impact on your entire server.

当您使用ASP.NET并行​​code,你正在决定要真正限制你的web应用程序的可伸缩性。您还可以看到线程流失了相当多的,特别是如果你的要求是突发性的。我建议只使用并行code对ASP.NET如果你的知道的那个并发用户的数量将是非常低的(即不是一个公共的服务器)。

When you use parallel code on ASP.NET, you are making the decision to really limit the scalability of your web app. You also may see a fair amount of thread churn, especially if your requests are bursty at all. I recommend only using parallel code on ASP.NET if you know that the number of simultaneous users will be quite low (i.e., not a public server).

所以,如果你走这么远了,你确定要在ASP.NET做并行处理,那么你有两个选择。

So, if you get this far, and you're sure you want to do parallel processing on ASP.NET, then you have a couple of options.

一个比较容易的方法是使用 Task.Run ,非常类似于现有的code。但是,我不建议实施 CalculateAsync 方法,因为这意味着处理是异步的(它不是)。相反,使用 Task.Run 在调用点:

One of the easier methods is to use Task.Run, very similar to your existing code. However, I do not recommend implementing a CalculateAsync method since that implies the processing is asynchronous (which it is not). Instead, use Task.Run at the point of the call:

private async Task MakeRequest()
{
  // do some stuff
  var task = Task.Run(() => Calculate(myInput));
  // do other stuff
  var myOutput = await task;
  // some more stuff
}

另外,如果你的code效果很好,你可以使用并行类型,例如,的Parallel.For Parallel.ForEach Parallel.Invoke 。到并行 code中的优点在于,请求的线程作为并行线程中的一个,然后在线程上下文恢复执行(有上下文小于切换在异步为例):

Alternatively, if it works well with your code, you can use the Parallel type, i.e., Parallel.For, Parallel.ForEach, or Parallel.Invoke. The advantage to the Parallel code is that the request thread is used as one of the parallel threads, and then resumes executing in the thread context (there's less context switching than the async example):

private void MakeRequest()
{
  Parallel.Invoke(() => Calculate(myInput1),
      () => Calculate(myInput2),
      () => Calculate(myInput3));
}

我不建议在ASP.NET中使用并行LINQ(PLINQ)都没有。

I do not recommend using Parallel LINQ (PLINQ) on ASP.NET at all.

这篇关于包装同步code到异步调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆