【问题标题】:async Controller with async Action doesn't work带有异步操作的异步控制器不起作用
【发布时间】:2016-02-09 11:32:00
【问题描述】:

我有带有异步操作的异步控制器。在操作中,我在 SomeMethodOne 中调用 WCF 服务方法(返回结果需要 10 秒),然后在 SomeMethodTwo 中执行一些数学运算(在我的计算机上执行大约 6 秒)。据我了解,在等待 WCF 服务方法的结果期间,我的计算机应该执行 SomeMethodTwo 但它没有执行,所有代码都执行 10 秒 + 6 秒 = 16 秒。为什么?

public class TestController : AsyncController
{
    public async Task<ActionResult> Index()
    {
        string result =  await SomeMethodOne();

        SomeMethodTwo();

        return View();
    }

    private async Task<string> SomeMethodOne() // it needs 10 seconds to return result from WCF service
    {
        using (Service1Client client = new Service1Client())
        {
            return await client.GetDataAsync(5);
        }
    }

    private void SomeMethodTwo() // it executes about 6 seconds on my computer
    {
        double result = 0;
        for (int i = 0; i < 1000000000; i++)
        {
            result += Math.Sqrt(i);
        }
    }
}

我在本地运行的 WCF 服务:

public class Service1 : IService1
{
    public string GetData(int value)
    {
        Thread.Sleep(10000);
        return string.Format("You entered: {0}", value);
    }        
}

【问题讨论】:

  • async 并不是说​​不需要16秒,而是需要16秒
  • 那么当我们调用单个 WCF 方法时,使用 async 的优势在哪里?
  • 异步只需确保您的线程已释放到应用程序池中,当操作完成时,它会再次从池中选择线程并开始执行下一个
  • 你能给我举个例子,使用异步控制器和动作更有意义吗?
  • AsyncController 已弃用。您只需在方法上使用async Task&lt;string&gt; 即可使其异步。

标签: c# asp.net-mvc asynchronous


【解决方案1】:

你的问题是你正在使用await

string result =  await SomeMethodOne();

await 表示您的控制器操作将在继续执行之前“异步等待”(等待)SomeMethodOne 的结果。

如果你想做异步并发,那就不要马上await。相反,您可以通过调用该方法开始异步操作,然后稍后再调用await

public async Task<ActionResult> Index()
{
  Task<string> firstOperation = SomeMethodOne();

  SomeMethodTwo();

  string result = await firstOperation;

  return View();
}

【讨论】:

  • 这个语句在这里不是同步的吗? Task&lt;string&gt; firstOperation = SomeMethodOne(); ?
  • @EhsanSajjad:嗯,你正在同步启动一个异步操作。
  • await 在这里的表现如何?
  • methodone 和methodtwo 都执行完后是不是不能到达await 行?
  • @EhsanSajjad:我的博客上有一个async intro,它解释了细节。
【解决方案2】:

然后然后我执行[强调我的]

做一件事,然后然后做另一件事,只要两者加在一起,就需要花很长时间。

同时做两件事可能会更快。由于上下文切换,它可能会更慢(想象有人做很多“多任务处理”并且花费更多时间在它们之间切换而不是工作)。如果您不必从第一个操作中获取结果来执行第二个操作,那么这里可能会更快:

public async Task<ActionResult> Index()
{
    Task<string> task =  SomeMethodOne();

    SomeMethodTwo();

    string result = await task;

    return View();
}

显然,如果您在调用SomeMethodTwo() 之前需要result,那么这是不可能的。 awaiting SomeMethodOne() 仍然有一个优势(如果可能的话,应该称为 SomeMethodOneAsync() 以符合 .NET 约定),因为如果 GetDataAsync() 是真正异步的,那么执行此操作方法的线程可以为您的 Web 应用程序的其他请求执行其他操作,当 I/O 操作返回数据时,另一个线程将开始处理这个请求。这无助于提高所涉及的单个方法的性能,但有助于在机器上针对所有 Web 请求运行的所有方法的整体可扩展性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-10
    • 2013-12-04
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 2013-07-28
    • 1970-01-01
    相关资源
    最近更新 更多