使用.net Core进行异步编程
本文关键字:异步 编程 net Core 使用 | 更新日期: 2023-09-27 18:01:57
我是.NET Core
和异步编程的新手。我正试图实现一个控制台应用程序来做以下事情:
-
控制台应用程序应该作为两个外部api之间的中介。如。API-1和API-2.
-
它应该在每10毫秒之后调用API-1来获取数据。
-
立即调用API-2提交从API-1接收到的数据
- 控制台应用程序需要等待API-1接收数据,但不必等待API-2的响应。
下面是我的代码。它没有像预期的那样工作。起初,它像预期的那样在10毫秒内调用API-1,但在此之后,它只在收到API-2的响应后才调用API-1。
所以假设API-2花了20秒,API-1也会在20秒后被调用。
我如何使API-2调用异步,使它不必等待API-2响应?
namespace ConsoleApp1
{
public class Program
{
private static Timer _timer;
private const int TIME_INTERVAL_IN_MILLISECONDS = 10; // 10 milliseconds
private const int API2_DELAY = 20000; // 20 seconds
public static void Main(string[] args)
{
Dowork().Wait();
Console.WriteLine("Press Any Key to stop");
Console.ReadKey();
Console.WriteLine("Done");
}
private static async Task Dowork()
{
var data = new SomeData();
_timer = new Timer(CallAPI1, data, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
await Task.Yield();
}
private static async void CallAPI1(object state)
{
var data = state as SomeData;
Console.WriteLine("Calling API One to get some data.");
data.SomeStringValue = DateTime.Now.ToString();
await CallAPI2(data);
_timer.Change(TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
}
private static async Task CallAPI2(SomeData data)
{
Console.WriteLine("Calling API Two by passing some data received from API One " + data.SomeStringValue);
// the delay represent long running call to API 2
await Task.Delay(API2_DELAY);
}
}
}
少类
namespace ConsoleApp1
{
public class SomeData
{
public string SomeStringValue { get; set; }
}
}
还要注意API-1和API-2将在ASP中开发。Core 1
Update1
让我把上面的句子改写一下。API-1将在。net核心中开发,而API-2将是windows工作流服务。这意味着我们可以给WF打多个电话。WF将保存请求并一次处理一个。
更新2
在浏览了所有提供的答案和链接之后。我正在考虑使用windows服务作为中介,而不是控制台应用程序。现在.Net core
不支持窗口服务,但有这个nuget-package,可以在windows服务中托管。net核心,或者我可能使用使用4.6.2的经典windows服务。我想我也可以在windows服务中实现异步。
在这种情况下,我有很多不同的做法。而不是使用定时器,我会使用Task.Delay
,也-我肯定会等待API2完成之前,试图扔更多的数据在它。此外,我会确保我的async
方法是Task
或Task<T>
返回,注意你的CallAPI1
调用不是,我理解它是一个计时器回调-但这是另一个问题。
考虑以下内容:
async Task IntermediateAsync()
{
Console.WriteLine("Press ESC to exit...");
while (Console.ReadKey(true).Key != ConsoleKey.Escape)
{
var result = await _apiServiceOne.GetAsync();
await _apiServiceTwo.PostAsync(result);
// Wait ten milliseconds after each successful mediation phase
await Task.Delay(10);
}
}
这将以以下方式起作用:
- 打印一行指示用户如何退出
- 开始循环
- 获取API1的结果
- 将结果传递给API2 等待10毫秒(步骤2)
最后,无论您是否使用.NET Core
,这都是相同的建议。任何API交互都应该遵循相同的指导原则。
在第二个API调用中使用"即发即弃"方法只会导致代码失败。由于这是一个API调用,因此I/O
绑定操作很可能会有一些延迟,并且应该假设10毫秒的紧密循环只会淹没该端点上的可用性。为什么不干脆等它做完呢,你有什么理由呢?
删除调用API2时的await
private static async void CallAPI1(object state)
{
var data = state as SomeData;
Console.WriteLine("Calling API One to get some data.");
data.SomeStringValue = DateTime.Now.ToString();
//Before this will cause the program to wait
await CallAPI2(data);
// Now it will call and forget
CallAPI2(data);
_timer.Change(TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
}
编辑:正如David指出的,当然有很多方法可以解决这个问题。这不是解决问题的正确方法。
另一种方法是使用quartz.net
- 将API1调度为重复作业
- 当API1完成时,调度另一个作业将API2作为独立作业运行
这样,当API2失败时,您可以重放/重复作业。