如何修复异步无法正常工作的问题?

问题描述 投票:0回答:1

我有一个调用 api 端点的脚本,但是当它发生奇怪的事情时,我什至无法解释它,所以我将向您展示代码并解释我得到的结果。

public class Program
{
    private static OpenSeaApiClient openSeaApiClient;
    private static Timer timer;
    private static int counter = 1;
    private static Collection galaxyEggs9999;


    static async Task Main()
    {
        string apiKey = "myKey";
        openSeaApiClient = new OpenSeaApiClient(apiKey);

        // Set up a timer to run the API calls every 10 seconds
        timer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
        timer.Elapsed += async (sender, e) => await TimerElapsedAsync();
        timer.Start();

        Console.WriteLine("Press Enter to exit.");
        Console.ReadKey();

        // Stop the timer when exiting the program
        timer.Stop();
        timer.Dispose();
    }

    private static async Task TimerElapsedAsync()
    {
        Console.WriteLine($"Counter: {counter++}");


        if (galaxyEggs9999 == null)
        {
            galaxyEggs9999 = new Collection(openSeaApiClient, "galaxyeggs9999", "0xA08126f5E1ED91A635987071E6FF5EB2aEb67C48");
        }
        await galaxyEggs9999.ExecuteAsync();
    //more instances

    }

所以 TimerElapsedAsync() 是用一个 Timer 设置的。 当 TimerElapsedAsync() 启动时,会打印 1 并且脚本进入对象的第一个实例。这个物体看起来像这样:

public class Collection
    {
        private readonly OpenSeaApiClient openSeaApiClient;
        private readonly string collectionName;
        private readonly string collectionContractAddress;
        public Collection(OpenSeaApiClient openSeaApiClient, string collectionName, string collectionContractAddress)
        {
            this.openSeaApiClient = openSeaApiClient;
            this.collectionName = collectionName;
            this.collectionContractAddress = collectionContractAddress;
        }
        public async Task ExecuteAsync()
        {
            //more code
                }
                else 
                {
                    var bestListingsResponse = await openSeaApiClient.GetBestListingsInCollectionResponse(CollectionName);
                    floorPriceInEtherDouble = GetCollectionFloorPriceInEther(bestListingsResponse);

                    //more code

问题来了——当脚本到达时

                    var bestListingsResponse = await openSeaApiClient.GetBestListingsInCollectionResponse(CollectionName);

2 被打印,之后是 3,4,5,然后脚本继续其他行。如果我在 GetBestListingsInCollectionResponse() 上放置一个断点并按 Step Over,它只会继续打印递增的数字,而不是继续。

如果这有帮助的话,这就是 GetBestListingsInCollectionResponse() 的样子。

 public async Task<string> GetBestListingsInCollectionResponse(string collectionSlug)
        {
            string endpoint = $"api/v2/listings/collection/{collectionSlug}/best";
            return await SendGetRequest(endpoint);
        }

我的代码中有更多端点,它们都不断做奇怪的事情,比如多次执行自己。

为什么会出现这种情况?

c# asynchronous timer
1个回答
1
投票

基于您正在运行的 API

System.Timers.Timer
,以及来自文档的备注部分

Timer
组件是一个基于服务器的计时器,在
Elapsed
属性中的毫秒数过去后,它会在应用程序中引发
Interval
事件。您可以使用
Timer
属性将
AutoReset
对象配置为仅引发一次或重复引发事件。

因此它不会等待处理程序完成,而是会在每次间隔过去时引发事件。

一种解决方法是将

AutoReset
设置为 false,然后在处理程序完成时启用计时器:

timer.AutoReset = false;
timer.Elapsed += (sender, eventArgs) =>
{
    Thread.Sleep(1000); // simulate some work
    Console.WriteLine("elapsed"); // simulate some work
    timer.Enabled = true; // do not forget to handle the exceptions
};

但是从 .NET 6 开始,您可以利用专为此类用例设计的

System.Threading.PeriodicTimer
(例如在 ASP.NET Core 后台工作人员中利用它 - 参见此处)。

© www.soinside.com 2019 - 2024. All rights reserved.