Queue of async tasks with throttling which supports muti-threading

前端 未结 5 687
傲寒
傲寒 2020-11-29 04:30

I need to implement a library to request vk.com API. The problem is that API supports only 3 requests per second. I would like to have API asynchronous.

5条回答
  •  爱一瞬间的悲伤
    2020-11-29 05:04

    I solved a similar problem using a wrapper around SemaphoreSlim. In my scenario, I had some other throttling mechanisms as well, and I needed to make sure that requests didn't hit the external API too often even if request number 1 took longer to reach the API than request number 3. My solution was to use a wrapper around SemaphoreSlim that had to be released by the caller, but the actual SemaphoreSlim would not be released until a set time had passed.

    public class TimeGatedSemaphore
    {
        private readonly SemaphoreSlim semaphore;
        public TimeGatedSemaphore(int maxRequest, TimeSpan minimumHoldTime)
        {
            semaphore = new SemaphoreSlim(maxRequest);
            MinimumHoldTime = minimumHoldTime;
        }
        public TimeSpan MinimumHoldTime { get; }
    
        public async Task WaitAsync()
        {
            await semaphore.WaitAsync();
            return new InternalReleaser(semaphore, Task.Delay(MinimumHoldTime));
        }
    
        private class InternalReleaser : IDisposable
        {
            private readonly SemaphoreSlim semaphoreToRelease;
            private readonly Task notBeforeTask;
            public InternalReleaser(SemaphoreSlim semaphoreSlim, Task dependantTask)
            {
                semaphoreToRelease = semaphoreSlim;
                notBeforeTask = dependantTask;
            }
            public void Dispose()
            {
                notBeforeTask.ContinueWith(_ => semaphoreToRelease.Release());
            }
        }
    }
    

    Example usage:

    private TimeGatedSemaphore requestThrottler = new TimeGatedSemaphore(3, TimeSpan.FromSeconds(1));
    public async Task MyRequestSenderHelper(string endpoint)
    {
        using (await requestThrottler.WaitAsync())
            return await SendRequestToAPI(endpoint);        
    }
    

提交回复
热议问题