当前位置: 首页 > 知识库问答 >
问题:

Web应用程序中的异步等待性能

龚承嗣
2023-03-14

到目前为止,我认为我已经掌握了async await如何使应用程序更具响应性的概念,但我有两点悬而未决:

层注意事项异步等待是否必须从存储库层一直到MVC或WCF层才能获得性能优势,或者我可以只对需要很长时间的存储库方法进行异步操作吗?

“等待”用法如果我只能在存储库级别工作,有一部分我不明白。使用这种(低层)方法,线程能够在等待io绑定代码完成的同时为传入的客户端请求提供服务吗?

在我看来,当长时间运行的任务仍在继续时,另一个用户可以向我的web应用程序发出请求,我收集了一个示例控制台应用程序。使用我的小库(以简化集成和异常处理),他们的请求是由挂起的线程提供服务,还是执行voidTask。等待() 导致线程阻塞?

public class AsyncTest
{
    public void RunTest()
    {
        try
        {
            using (var task = new RunTask(LongRunningTask))
            {
                Console.WriteLine("Echo two things:");

                for (int i = 0; i < 2; i++)
                {
                    var input = Console.ReadLine();
                    Console.WriteLine(string.Format("Echoing \"{0}\"", input));
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Error, hm, what happened??");
            Console.WriteLine();
            Console.WriteLine(e.Message);
            Console.WriteLine(e.StackTrace);
        }
    }

    public void LongRunningTask()
    {
        var totals = 0;

        for (int i = 0; i < 30; i++)
        {
            Thread.Sleep(1000);
            totals += 5;

            if (i == 25)
                throw new ArgumentException("I can't handle this! Errorr!!@!@");

            Console.WriteLine(string.Format("LongRunningTask Step {0}...", (i + 1)));
        }
    }
}

public class RunTask : IDisposable
{
    public delegate void IOBoundOperations();
    private Task voidTask;

    public RunTask(IOBoundOperations task)
    {
        voidTask = Execute(task);
    }

    async public Task Execute(IOBoundOperations task)
    {
        await Task.Run(() =>
        {
            task();
        });
    }

    public void Dispose()
    {
        try
        {
            voidTask.Wait();
        }
        catch
        {
            throw new AsyncException("Failed to run task asynchronously: " + 
                voidTask.Exception.InnerException.Message, voidTask.Exception.InnerException);
        }
    }
}

我把它放在等待中,因为我将需要它来执行任务,这些任务将向它可能依赖的调用代码返回数据。我之所以这样做,也是因为我注意到,在线程执行完异步内容之前,进程不会完成。

我可以找到很多关于async/await的信息,以及它的好处,但在这一方面没有任何内容。

共有3个答案

法风畔
2023-03-14

对于异步IO的好处,您似乎没有很好的理解。它取消阻止线程,从而节省堆栈内存并避免线程池容量过载。

等待显然会阻塞线程,因为该函数在目标任务完成之前不会返回。在调用期间,线程资源被消耗。

您需要使整个调用链异步。如果只使下层异步,则必须在上层等待,并消耗与所保存的线程数量相同的线程。

请注意,大多数web应用程序都无法通过使用异步IO来提高吞吐量或降低延迟。您必须了解异步IO的好处,才能进行良好的调用。不要沉迷于炒作。请参见我们是否应该切换到默认情况下使用异步I/O?为什么EF 6教程使用异步调用?。

穆文斌
2023-03-14

要从async/wait范式中获得任何好处,您将希望将其一直带到顶部,无论是您的MVC/Web API操作(通过将操作标记为async并返回某种类型的任务)或在您的Web窗体方法中(通常通过将它们标记为async val,并在页面本身设置Async属性)。

除此之外,您只有两个选择:

  • 调用任务。Wait(),这会使其阻塞,因此不会出现任何异步行为

尽管如此,您提到如果您这样做,其他用户可以调用您的Web服务器,这是真的,但重要的是要注意ASP Web应用程序总是“异步”的,因为它们有许多线程可供它们使用。实现async/wait原则上是一个好主意,它有助于提高这些分配线程的效率,并可能增加可用并发连接的数量,但不需要允许同时满足两个并发请求。线程池将自行处理。

如果您担心遍历整个代码库并用它们的交换同步调用。。。Async()对等,请记住,您不必一次完成所有操作。如果可以,这很好,因为异步调用有前面列出的一些优点,但请记住,您可以将return方法设置为returnTask。FromResult(object)支持异步约定。

显然,这不会异步进行,但在迁移现有代码或编写库时,最好记住这一点,因为时间只会让越来越多的东西实现该模式,您可以现在就设计好欢迎它,而不是希望以后再这样做。

宗政斌
2023-03-14

正如其他人所说,您并没有通过示例真正掌握异步IO的真正功能。

当人们意识到异步“一路走”,从存储库一直走到控制器时,他们通常会感到“害怕”。正如我经常说的,不要反对它,让它在您开始实现时自然地在您的代码库中增长。我建议不要对sync over async进行任何快捷操作,反之亦然,如果需要的话,可以额外努力(如果需要的话)分别公开这两个API。

但是,正如@usr所说,并不总是需要实际执行异步IO,即使这是可能的。当然,每个人都想驾驭async-wait的潮流,因为这是一件很酷的事情,但之前问问自己,我是否会遇到很多并发请求,而我实际上会从异步IO中受益?不要忘记,虽然async-wait很少,但它确实有一些开销。

最后,一个小小的个人故事。最近我开始研究ASP。NET Web API项目,该项目正在访问SQL数据库并进行一些繁重的计算。挑战在于使计算速度更快,我想知道使数据库调用异步是否会有帮助(我有种直觉认为不会,但我必须尝试)。在添加异步API并在方法中使用它之后(这本身不是一件小事),总体性能实际上会下降(正如我所假设的)。因此,请确保出于正确的原因利用异步IO。

 类似资料:
  • 我试图在react/electron项目中使用async/await,但它不起作用。我想要的是获取docker容器状态列表。但是安慰。日志(列表)返回未定义的。 有人能帮我吗?:)

  • 我使用Java中的创建一个线程池,每个线程在其中执行一些异步任务/调用另一个服务。我不想等待回复,但无论何时回复都会返回。 这样做将等待第一个请求完成,然后返回结果。问题是,第二个请求必须等待第一个请求的响应返回,并且只有在这之后才会被处理。如果我使用CompletableFuture的方法,也会发生同样的情况,因为我还必须使用来获取响应。 我希望所有的请求都经过检查,并在收到时返回回复。这是可以

  • 我正在尝试将数据库调用移出控制器,以清理并使其可测试。当它们在控制器中时,一切都会顺利进行。我将它们移出控制器,并添加了一个异步,以确保我们等待。否则,我将调用的中的函数。现在,一旦我使用async/await,控制器中的函数就会认为没有用户,因为它没有等待。 有几个关于异步等待的SO问题,但我没有找到一个解决我的问题。我确实验证了返回了我的用户,并添加了控制台日志来显示路径。 节点猫鼬异步等待似

  • 任务或任务 我们也可以定义自己的可实现对象。对象应具有以下资格。 < li >它有一个GetAwaiter()方法(实例方法或扩展方法); < li >其GetAwaiter()方法返回一个Awaiter。在下列情况下,对象是一个标识符: < ul > < li >它实现INotifyCompletion或ICriticalNotifyCompletion接口; < li >它有一个IsCompl

  • 我想进行一个基于当前状态的API调用,但不能使setState函数作为异步函数工作。 给我错误: 类型为“”的参数(状态:只读)= 如果我在setState方法之外获取数据,它会起作用,但我害怕对过时的页码进行API调用:

  • 我通读了Dart/flatter中的Async/Await/then,试图理解为什么aysnc函数中的Await不会等到完成后再继续。在我的UI中,有一个按钮调用一个异步方法来返回一个位置,该位置总是返回null,并且不等待函数完成。 该函数将调用推送到一个新的UI页面,该页面选择一个位置,并应返回一个结果。如何使该函数等待结果?我不是在使用异步吗?