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

C#async/wait在无服务器上下文中有什么好处?

郑光济
2023-03-14

对于简单地调用外部服务或写入数据存储的微服务函数,在C#中使用async/wait有什么意义吗?

我们在AWS Lambdas中编写了大量这样的代码,很难确定async/await在这种情况下的实际收益是什么,或者它到底在哪里有用。对于更传统的IIS web服务,异步释放操作系统中的线程,并允许服务器服务更多请求。

但对于AWS Lambdas,这些函数每次执行仅处理一个请求(限制为1000次同时执行)。因此,如果我们有一个长时间运行的外部进程或具有显著延迟的外部依赖关系,那么每个函数的执行都将被挂起,直到外部进程完成(假设Lambda是同步调用的)。

这是一个具有三个处理程序的示例Lambda,我将其中的第三个放在一个单独的Lambda中,称为“DavidSleep”,它只是表示一个长期运行的外部依赖。当我使用前两个处理程序中的任何一个调用另一个名为“DavidTest”的Lambda时,我发现异步/等待版本与缺少异步/等待的版本在功能或性能上没有差别。这两个函数都需要多个并发Lambda执行,并且需要相同的时间。

因此,异步版本似乎与无异步版本没有区别,但有什么区别吗?

public class Test
{
    private IAmazonLambda lambda;

    public Test()
    {
        lambda = new AmazonLambdaClient();
    }

    [LambdaSerializer(typeof(JsonSerializer))]
    public async Task HandleAsync(Request request)
    {
        Console.WriteLine($"Executing for { request.Name }");
        await lambda.InvokeAsync(new InvokeRequest
        {
            FunctionName = "DavidSleep",
            InvocationType = InvocationType.RequestResponse,
            Payload = JsonConvert.SerializeObject(request)
        });
    }

    [LambdaSerializer(typeof(JsonSerializer))]
    public void Handle(Request request)
    {
        Console.WriteLine($"Executing for { request.Name }");
        lambda.InvokeAsync(new InvokeRequest
        {
            FunctionName = "DavidSleep",
            InvocationType = InvocationType.RequestResponse,
            Payload = JsonConvert.SerializeObject(request)
        }).Wait();
    }

    [LambdaSerializer(typeof(JsonSerializer))]
    public void Sleep(Request request)
    {
        Console.WriteLine($"{ request.Name }{ request.RequestId } begin");
        Thread.Sleep(request.WaitInSeconds * 1000);
        Console.WriteLine($"{ request.Name }{ request.RequestId } end");
    }
}

共有3个答案

楚俊逸
2023-03-14

Async和await很容易使用,但很难理解。在完成了10多年的C语言编程之后,我仍然无法理解所涉及的每一个机械师。让我只提两件事:任务。等等,任务。Run、BlockingCollection、lock语句、ConfigureAwait、CancellationToken、TaskCompletionSource等

因此,除非您只与高级C#程序员打交道,而且您也是其中之一,否则我会尽可能避免使用异步/等待。有一条规则,你不应该过早地优化你的代码。如果您有需要结果的内容,async/await无论如何都不会帮助您,因为只要您请求结果,您仍然会被阻止。但是,您可以通过在后台线程中运行异步/等待来推迟获得结果。

我正在同步编写所有代码。如果我阻止我的UI,那么我知道我可以使用async/await来避免它,因为UI希望我这样做。但是UI在最终处理之前不会显示结果。这就是为什么我说我被封锁了。仅仅因为该行可能在调试器中执行,并不意味着结果将实际出现在UI中。

当我识别出一个实际上阻止我进一步处理数据的调用时,我希望它发生在一个单独的线程中,那么使用async/wait当然是有意义的。

如果您有一个服务器,它获取一个查询,并将结果发送给客户端,那么就不需要异步/等待,因为使用每一种魔术,如果没有时间旅行,服务器将无法在完成之前将结果发送给客户端。

但是,如果服务器需要并行处理多个查询并返回结果,则在单独的线程中处理每个结果是有意义的。因此,您希望在处理结果的任何地方都有asyn/wait。否则,您的整个服务器可能会被阻止,因为它正在处理单个结果,而其他服务器试图同时到达,但无法处理,因为服务器仍忙于获取第一个查询的结果。

萧建木
2023-03-14

这里讨论了两个案例:

  • 在Lambda函数中使用的C#代码中异步等待

Lambda函数中C#代码中的异步/等待模式Lambda执行框架不关心代码的执行方式,它只调用。Net framework执行代码并等待执行完成。在函数内部,这是通常的异步/等待模式优势<如果以异步方式启动长操作,然后使用主线程执行不依赖于长操作结果的其他操作,则C代码中的异步/等待功能非常有用。如果函数中有一个长操作,则异步和同步执行是相似的。使用异步而不是同步没有任何好处(事实上,正如上面的注释所指出的,使用异步机制可能会有一些开销)。

异步调用lambda函数与同步调用
问题描述了这种差异的一个示例——使用异步方法和同步方法调用长时间运行的lambda。出于合理的原因,没有观察到任何变化。同样,异步调用只有在主线程可以执行不依赖于异步方法结果的不同操作时才是有益的。该示例仅显示了对lambda的调用。因此,主线程必须等待其在异步和同步情况下的执行完成。它没有利用其他执行的等待时间,因此执行所需的总时间没有差异。

Async的场景
假设有2个lambda函数,DavidSpt和JohnSpt需要并行调用,相互独立。DavidSpt执行需要1秒,JohnSpt执行需要2秒。如果在上面的HandleAsync()中调用这两个函数,则总执行时间将为〜2秒(加上异步开销的几毫秒)
如果在上面的Handle()中调用这些函数,则总执行时间将为〜3秒(加上几毫秒)

严宸
2023-03-14

在无服务器上下文中使用async/await的好处仍然是,您可以获得对调用线程的控制,从而释放另一个调用方来使用该线程。我不知道AWS是否会从1000次呼叫限制中删除等待呼叫,但他们可能会这样做。

对于这些在方法中没有其他异步调用的单行程序样式的任务调用,您可以简单地返回任务。无论AWS Lambda 1000调用限制如何,将方法标记为async和调用Wait都会增加不必要的开销。

示例:

[LambdaSerializer(typeof(JsonSerializer))]
public Task HandleAsync(Request request)
{
    Console.WriteLine($"Executing for { request.Name }");
    return lambda.InvokeAsync(new InvokeRequest
    {
        FunctionName = "DavidSleep",
        InvocationType = InvocationType.RequestResponse,
        Payload = JsonConvert.SerializeObject(request)
    });
}
 类似资料:
  • 问题内容: 我正在编写一个脚本,该脚本应该在一堆服务器周围运行,并从其中选择一堆数据,包括本地服务器。选择所需数据的SQL非常复杂,因此我正在编写临时视图,并使用OPENQUERY语句获取数据,因此最终我最终循环了如下语句: 但是,我听说在本地服务器上使用OPENQUERY是一种皱眉。有人能详细说明为什么吗? 问题答案: 尽管查询可能返回多个结果集,但OPENQUERY仅返回第一个结果集。 OPE

  • 我正在做一个应用程序使用flutter框架。在此过程中,我遇到了Dart和中的关键字。谁能告诉我它们有什么不同吗?

  • 想改进这个问题吗 通过编辑此帖子,更新问题,使其只关注一个问题。 我试图理解Wait async在C中是如何工作的,有一件事让我很困惑。我知道任何使用await关键字的方法都必须标记为async。我的理解是,当命中带有await关键字的行时,该行下面的代码不会执行。启动异步操作以在等待行中执行语句,并将控件返回给可以继续执行的调用方法。 问题#1:这个假设是正确的还是wait关键字下面的代码仍在执

  • 我正在使用.NET 4 C。我正在尝试上载一个ZIP文件,然后将其下载到(我的)服务器。 上传我有 这似乎可行,因为我在服务器上得到了一个大小合适的文件。 1) 我如何将其流式传输,而不是首先将其加载到内存中?我将上传非常大的文件。 为了下载我有 2)一切似乎都正常......除了当我尝试解压缩下载的ZIP文件时,我得到了一个无效的ZIP文件。

  • 问题内容: 我们都知道 单身 人士有多 糟糕 ,因为他们隐藏了依赖关系以及其他原因。 但是在一个框架中,可能有许多对象只需要实例化一次,并可以 从任何地方 调用(记录器,数据库等)。 为了解决这个问题,有人告诉我使用所谓的“对象管理器”(或诸如symfony之类的服务容器),在内部存储对服务(记录器等)的所有引用。 但是,为什么服务提供者不像单纯的Singleton那样糟糕? 服务提供者也隐藏了依

  • 问题内容: 我正在编写一些返回JSON数据的Web服务,这些用户有很多用户。 与仅使用go http服务器相比,在服务器前端使用Nginx有什么好处? 问题答案: 这取决于。 开箱即用,将nginx放在前面作为反向代理将为您提供: 访问日志 错误日志 轻松终止SSL SPDY支持 gzip支持 在几行中为某些路由设置HTTP标头的简单方法 非常快速的静态资产服务(不过,如果您要使用S3 / etc