简体   繁体   English

c# 我可以使用可丢弃来避免等待异步 function 调用吗?

[英]c# can i use discardable to avoid awaiting on an async function call?

I have a synchronous function GetUserStatus() which in turn calls an async function LogAsync() .我有一个同步的 function GetUserStatus() ,它又调用异步 function LogAsync()

I do not want to await on LogAsync() but that doesn't seem to be something done as simple as it is to declare await.我不想在LogAsync()上等待,但这似乎不像声明等待那么简单。 I was just hoping it's a matter of not awaiting, but no.我只是希望这是一个不等待的问题,但没有。

I know there are approaches like using .ContinueWith() , but in this particular case I want to know if just discarding the call to LogAsync() will let the current thread continue without waiting on LogAsync() to complete?我知道有使用.ContinueWith()之类的方法,但在这种特殊情况下,我想知道是否只是放弃对LogAsync()的调用会让当前线程继续而不等待LogAsync()完成?


Preferred pseudocode Setup :首选伪代码设置

Public UserStatus GetUserStatus(){
    var status = GenerateStatus();
    _logger.LogAsync("Current Status: " + status.description()); //invoke and forget
    return status;
}

Reality pseudocode :现实伪代码

Public async UserStatus GetUserStatus(){
    var status = GenerateStatus();
    await _logger.LogAsync("Current Status: " + status.description()); //I don't want to wait for this
    return status;
}

Will using discardable work like this?会像这样使用可丢弃的工作吗? :

Public UserStatus GetUserStatus(){
    var status = GenerateStatus();
    _ = _logger.LogAsync("Current Status: " + status.description()); //will this await?
    return status;
}

In this last case, will GetUserStatus() wait for LogAsync() or will it just continue right after the call?在最后一种情况下,GetUserStatus() 会等待 LogAsync() 还是会在调用后立即继续?

The simple answer is: yes, you can use a discarable to avoid waiting for LogAsync to complete.简单的答案是:是的,您可以使用可丢弃来避免等待LogAsync完成。 (You don't technically need to use the discard, but doing so avoids a compiler warning telling you that you're not awaiting it.) (从技术上讲,您不需要使用丢弃,但这样做可以避免编译器警告告诉您您没有在等待它。)

However, you should understand what's actually happening before you do that.但是,在您这样做之前,您应该了解实际发生的情况。

What spender is saying in the comments is that all asynchronous methods start running synchronously, and will return at the first await that acts on an incomplete Task .花费者在评论中说的是所有异步方法都开始同步运行,并将在第一个await不完整的Task时返回。 In a method like LogAsync , that would be whenever it stores the log entry to whatever storage medium it's going to (file system or database, for example).在像LogAsync这样的方法中,只要它将日志条目存储到它将要存储的任何存储介质(例如文件系统或数据库)。 Once that I/O request is started , then it returns and GetUserStatus can continue.一旦该 I/O 请求启动,它就会返回并且GetUserStatus可以继续。 Usually, that's fine.通常,这很好。 The code before the I/O request is usually very minimal. I/O 请求之前的代码通常非常少。

If you really wanted to not wait for any of the code in LogAsync , then you could move it to a new thread:如果您真的不想等待LogAsync中的任何代码,则可以将其移至新线程:

_ = Task.Run(() => _logger.LogAsync("Current Status: " + status.description()));

However, that's not free (there is overhead to that).但是,这不是免费的(有开销)。 And if this is an ASP.NET application, that's not a great idea since ASP.NET has a limited number of threads so, depending on the load of your application, it may bring you dangerously close to hitting that max.如果这是一个 ASP.NET 应用程序,这不是一个好主意,因为 ASP.NET 的线程数量有限,因此,根据应用程序的负载,它可能会让您危险地接近达到最大值。 In my opinion, it's not worth it.在我看来,这不值得。 I don't think you'll be gaining anything.我不认为你会得到任何东西。

The dangers危险

This whole idea is called "fire and forget".这整个想法被称为“一劳永逸”。 The "forget" is the danger that you need to weigh. “忘记”是你需要权衡的危险。 Because you're forgetting it, you have no way to know if it completed successfully.因为你忘记了它,所以你无法知道它是否成功完成。 It could be a database error for example, but also, in the case of ASP.NET, if the app pool is ever restarted, IIS will kill the process once it knows that all HTTP requests have finished processing.例如,这可能是数据库错误,但在 ASP.NET 的情况下,如果应用程序池重新启动,IIS 将在知道所有 Z293C9EA246FF9985DC6F62A650F78986 请求已完成处理后终止该进程。 It has no idea if any background jobs are running (like a fire and forget task).它不知道是否有任何后台作业正在运行(如火灾并忘记任务)。 So there is the possibility of it being killed.所以有被杀的可能。

The logging could fail and you'll never know.日志记录可能会失败,你永远不会知道。 Sure, 99.9999% of the time it'll be fine.当然,99.9999% 的时间它会没事的。 But only you can answer if you can tolerate any log messages being lost without you ever knowing.但是,只有您可以容忍任何日志消息在您不知道的情况下丢失,您才能回答。

If you want to mitigate that risk, there are other ways of handling it in ways that can be more described like "do this later" rather than "fire and forget".如果你想减轻这种风险,还有其他方法可以用更描述的方式来处理它,比如“稍后再做”而不是“一劳永逸”。 One library that helps with that is Hangfire (I've never used it, but I've seen it discussed).一个对此有所帮助的库是Hangfire (我从未使用过它,但我已经看到过它的讨论)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM