为什么SemaphoreSlim没有在异步Task中发布?

时间:2018-10-26 16:34:18

标签: c# .net async-await semaphore

我需要尽快调用API数千次。该API每秒不得超过10个调用。为了充分利用每秒的10个调用而不进行切换,我异步调用API,并使用信号量和计时器来限制调用。我的代码进入了信号量,调用了API,然后确保在释放信号量之前至少经过了一秒钟。

实际上,API调用非常快,并且返回的时间大约为一秒或更短,因此我的代码应直接移至检查时间/释放信号量逻辑。但是,实际发生的情况是在10次调用后信号量已满,并且直到创建调用API的其余异步任务后才释放。之后,一切都会按预期进行,因此我没有遇到任何实际问题。这种行为看起来很奇怪,我想理解。

public static class MyClass 
{
    SemaphoreSlim semaphore = new SemaphoreSlim(10);

    public static async Task CreateCallApiTasks(IList<object> requests)
    {
        var callApiTasks = requests.Select(x => CallApi(x));
        await Task.WhenAll(callApiTasks);
    }

    private static async Task CallApi(object requestBody)
    {
        using (var request = new HttpRequestMessage(HttpMethod.Post, <apiUri>))
        {
            request.Content = new StringContent(requestBody, System.Text.Encoding.UTF8, "application/json");
            HttpResponseMessage response = null;

            using (var httpClient = new HttpClient())
            {
                var throttle = new Stopwatch();
                ExceptionDispatchInfo capturedException = null;

                await semaphore.WaitAsync();

                try
                {
                    throttle.Start();
                    response = await httpClient.SendAsync(request);

                    while (throttle.ElapsedMilliseconds < 1000)
                    {
                        await Task.Delay(1);
                    }

                    semaphore.Release();
                    throttle.Stop();
                }
                catch (Exception ex)
                {
                    capturedException = ExceptionDispatchInfo.Capture(ex);
                }

                if (capturedException != null)
                {
                    while (throttle.ElapsedMilliseconds < 1000)
                    {
                        await Task.Delay(1);
                    }

                    semaphore.Release();
                    throttle.Stop();                
                    capturedException.Throw();
                }
            }
        }
    }
}

0 个答案:

没有答案