启动和异步即发即弃调用的正确方法?
Proper way to start and async fire-and-forget call?
我有一个异步调用 (DoAsyncWork()
),我想以一劳永逸的方式开始,即我对其结果不感兴趣,希望调用线程继续甚至在异步方法完成之前。
正确的做法是什么?我在 .NET Framework 4.6 和 .NETCore 2 中都需要这个,以防出现差异。
public async Task<MyResult> DoWorkAsync(){...}
public void StarterA(){
Task.Run(() => DoWorkAsync());
}
public void StarterB(){
Task.Run(async () => await DoWorkAsync());
}
是这两个之一还是什么different/better?
//编辑:理想情况下没有任何额外的库。
这取决于你的意思:)
例如:您对 "fire and forget" 调用中抛出的异常感兴趣吗?如果没有,那还好。尽管您可能需要考虑的是任务所处的环境。
例如,如果这是一个 asp.net 应用程序,并且您在由于调用 .aspx 或 .svc 而实例化的线程的生命周期内执行此操作。任务成为该(前台)线程的后台线程。在您的 "fire and forget" 任务完成之前,前台线程可能会被应用程序池清理。
所以还要考虑你的任务在哪个线程中。
我认为这篇文章为您提供了一些有用的信息:
https://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
另请注意,如果您没有 return 任务中的值,任务将不会 return 异常信息。其来源是微软考试 70-483 的参考书
网上某个地方可能有一个免费版本;P https://www.amazon.com/Exam-Ref-70-483-Programming-C/dp/0735676828
如果您有一个由非异步调用的异步方法并且您希望知道其结果,知道这一点可能很有用。您可以使用 .GetAwaiter().GetResult().
另外我认为注意异步和多线程之间的区别很重要。
异步仅在有操作使用计算机的其他部分而不是 CPU 时才有用。所以诸如网络或 I/O 操作之类的东西。然后使用异步告诉系统继续并在其他地方使用 CPU 电源而不是 CPU 中的 "blocking" 那个线程只是等待响应。
多线程是 CPU 中不同线程上的操作分配(例如,创建一个创建前台线程的后台线程的任务......前台线程是组成的线程你的应用程序,它们是主要的,后台线程存在链接到前台线程。如果你关闭链接的前台线程,后台线程也会关闭)
这允许 CPU 同时处理不同的任务。
将这两者结合起来可以确保 CPU 如果是一个 4 线程 CPU 则不会只在 4 个线程上被阻塞。但是在等待等待 I/O 操作的异步任务时可以打开更多。
我希望这能为您提供所需的信息,无论您在做什么:)
What is the proper way to do this?
首先,你需要决定你是否真的想要fire-and-forget。根据我的经验,大约 90% 的提出此要求的人实际上 不 想要即发即弃;他们想要后台处理服务。
具体来说,即发即弃意味着:
- 您不关心操作何时完成。
- 你不关心执行动作时有没有异常。
- 您根本不关心操作是否完成。
因此,即发即弃的现实世界用例非常少。像更新服务器端缓存这样的操作就可以了。发送电子邮件、生成文档或任何业务相关不 OK,因为您 (1) 希望操作完成,并且 (2 ) 在操作出错时收到通知。
绝大多数时候,人们根本不想要即发即弃;他们想要后台处理服务。构建其中一个的正确方法是添加一个可靠的队列(例如,Azure Queue / Amazon SQS,甚至一个数据库),并拥有一个独立的后台进程(例如,Azure Function / Amazon Lambda / .NET Core BackgroundService / Win32服务)处理该队列。这本质上就是 Hangfire 提供的(使用数据库作为队列,运行 后台进程 in-proc 在 ASP.NET 进程中)。
Is it one of those two or something different/better?
一般情况下,there's a number of small behavior differences when eliding async
and await
。这不是你想做的事 "by default".
但是,在这种特定情况下 - async
lambda 仅调用单个方法 - 省略 async
和 await
没问题。
我有一个异步调用 (DoAsyncWork()
),我想以一劳永逸的方式开始,即我对其结果不感兴趣,希望调用线程继续甚至在异步方法完成之前。
正确的做法是什么?我在 .NET Framework 4.6 和 .NETCore 2 中都需要这个,以防出现差异。
public async Task<MyResult> DoWorkAsync(){...}
public void StarterA(){
Task.Run(() => DoWorkAsync());
}
public void StarterB(){
Task.Run(async () => await DoWorkAsync());
}
是这两个之一还是什么different/better?
//编辑:理想情况下没有任何额外的库。
这取决于你的意思:)
例如:您对 "fire and forget" 调用中抛出的异常感兴趣吗?如果没有,那还好。尽管您可能需要考虑的是任务所处的环境。
例如,如果这是一个 asp.net 应用程序,并且您在由于调用 .aspx 或 .svc 而实例化的线程的生命周期内执行此操作。任务成为该(前台)线程的后台线程。在您的 "fire and forget" 任务完成之前,前台线程可能会被应用程序池清理。
所以还要考虑你的任务在哪个线程中。
我认为这篇文章为您提供了一些有用的信息: https://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
另请注意,如果您没有 return 任务中的值,任务将不会 return 异常信息。其来源是微软考试 70-483 的参考书 网上某个地方可能有一个免费版本;P https://www.amazon.com/Exam-Ref-70-483-Programming-C/dp/0735676828
如果您有一个由非异步调用的异步方法并且您希望知道其结果,知道这一点可能很有用。您可以使用 .GetAwaiter().GetResult().
另外我认为注意异步和多线程之间的区别很重要。
异步仅在有操作使用计算机的其他部分而不是 CPU 时才有用。所以诸如网络或 I/O 操作之类的东西。然后使用异步告诉系统继续并在其他地方使用 CPU 电源而不是 CPU 中的 "blocking" 那个线程只是等待响应。
多线程是 CPU 中不同线程上的操作分配(例如,创建一个创建前台线程的后台线程的任务......前台线程是组成的线程你的应用程序,它们是主要的,后台线程存在链接到前台线程。如果你关闭链接的前台线程,后台线程也会关闭) 这允许 CPU 同时处理不同的任务。
将这两者结合起来可以确保 CPU 如果是一个 4 线程 CPU 则不会只在 4 个线程上被阻塞。但是在等待等待 I/O 操作的异步任务时可以打开更多。
我希望这能为您提供所需的信息,无论您在做什么:)
What is the proper way to do this?
首先,你需要决定你是否真的想要fire-and-forget。根据我的经验,大约 90% 的提出此要求的人实际上 不 想要即发即弃;他们想要后台处理服务。
具体来说,即发即弃意味着:
- 您不关心操作何时完成。
- 你不关心执行动作时有没有异常。
- 您根本不关心操作是否完成。
因此,即发即弃的现实世界用例非常少。像更新服务器端缓存这样的操作就可以了。发送电子邮件、生成文档或任何业务相关不 OK,因为您 (1) 希望操作完成,并且 (2 ) 在操作出错时收到通知。
绝大多数时候,人们根本不想要即发即弃;他们想要后台处理服务。构建其中一个的正确方法是添加一个可靠的队列(例如,Azure Queue / Amazon SQS,甚至一个数据库),并拥有一个独立的后台进程(例如,Azure Function / Amazon Lambda / .NET Core BackgroundService / Win32服务)处理该队列。这本质上就是 Hangfire 提供的(使用数据库作为队列,运行 后台进程 in-proc 在 ASP.NET 进程中)。
Is it one of those two or something different/better?
一般情况下,there's a number of small behavior differences when eliding async
and await
。这不是你想做的事 "by default".
但是,在这种特定情况下 - async
lambda 仅调用单个方法 - 省略 async
和 await
没问题。