如何使用任务.延迟用于控制对web服务的调用之间的时间跨度

本文关键字:服务 调用 之间 时间跨度 web 任务 何使用 延迟 用于 控制 | 更新日期: 2023-09-27 18:18:34

当用户执行某个操作时,将对web服务进行调用(get)。该服务不允许通话频率超过每秒一次。我想我可以用任务组。延迟控制这一点,以便后续呼叫至少间隔一秒钟,但它似乎不像预期的那样工作。伪代码看起来像这样:

public async void OnUserAction()
{
    var timeUntilPreviousCallWillBeOrWasMade = 1000ms - (Now - previousWaitStartTime);
    var timeToWaitBeforeThisCallShouldBeMade = Max(0, timeUntilPreviousCallWillBeOrWasMade + 1000ms);
    previousWaitStartTime = Now;
    await Task.Delay(timeToWaitBeforeThisCallShouldBeMade);
    MakeCallToWebService();
}

调用和延续在同一个线程上完成(由Environment.CurrentManagedThreadId报告)。问题是,如果这个方法有一个快速的连续调用,那么调用web服务之间的间隔时间小于15秒。要么我犯了一个愚蠢的错误,要么我没有完全理解Task。延迟(或两者都延迟)。有提示吗?

如何使用任务.延迟用于控制对web服务的调用之间的时间跨度

当另一个请求已经在等待时,您的问题似乎发生在请求排队时。以下是我对你的伪代码的看法:

using System;
using System.Threading;
using System.Threading.Tasks;
namespace ThrottledAsync
{
    class Program
    {
        static void Main(string[] args)
        {
            // Queue up multiple user actions
            // within a short interval.
            for (var i = 0; i < 10; i++)
            {
                OnUserAction();
                Thread.Sleep(10);
            }
            Console.ReadLine();
        }
        private static int UserActionID;
        private static DateTime previousWaitStartTime;
        public static async void OnUserAction()
        {
            // Keep track of the operation ID.
            var userActionID = Interlocked.Increment(ref UserActionID);
            // Pseudo-code implementation.
            var timeUntilPreviousCallWillBeOrWasMade = 1000 - (int)(DateTime.Now.Subtract(previousWaitStartTime).TotalMilliseconds);
            Console.WriteLine(
                "{0:HH:mm:ss.ffff} - User action {1}: timeUntilPreviousCallWillBeOrWasMade = {2}.",
                DateTime.Now, userActionID, timeUntilPreviousCallWillBeOrWasMade);
            var timeToWaitBeforeThisCallShouldBeMade = Math.Max(0, timeUntilPreviousCallWillBeOrWasMade + 1000);
            Console.WriteLine(
                "{0:HH:mm:ss.ffff} - User action {1}: timeToWaitBeforeThisCallShouldBeMade = {2}.",
                DateTime.Now, userActionID, timeToWaitBeforeThisCallShouldBeMade);
            previousWaitStartTime = DateTime.Now;
            await Task.Delay(timeToWaitBeforeThisCallShouldBeMade);
            await MakeCallToWebService(userActionID);
        }
        private static async Task MakeCallToWebService(int userActionID)
        {
            // Simulate network delay.
            await Task.Delay(new Random().Next(5, 10));
            Console.WriteLine("{0:HH:mm:ss.ffff} - User action {1}: web service call.", DateTime.Now, userActionID);
        }
    }
}

输出:

19:10:11.1366 - User action 1: timeUntilPreviousCallWillBeOrWasMade = -2147482648.
19:10:11.1416 - User action 1: timeToWaitBeforeThisCallShouldBeMade = 0.
19:10:11.1536 - User action 2: timeUntilPreviousCallWillBeOrWasMade = 988.
19:10:11.1536 - User action 2: timeToWaitBeforeThisCallShouldBeMade = 1988.
19:10:11.1586 - User action 1: web service call.
19:10:11.1646 - User action 3: timeUntilPreviousCallWillBeOrWasMade = 990.
19:10:11.1646 - User action 3: timeToWaitBeforeThisCallShouldBeMade = 1990.
19:10:11.1756 - User action 4: timeUntilPreviousCallWillBeOrWasMade = 990.
19:10:11.1756 - User action 4: timeToWaitBeforeThisCallShouldBeMade = 1990.
19:10:11.1866 - User action 5: timeUntilPreviousCallWillBeOrWasMade = 990.
19:10:11.1866 - User action 5: timeToWaitBeforeThisCallShouldBeMade = 1990.
19:10:11.1976 - User action 6: timeUntilPreviousCallWillBeOrWasMade = 990.
19:10:11.1986 - User action 6: timeToWaitBeforeThisCallShouldBeMade = 1990.
19:10:11.2086 - User action 7: timeUntilPreviousCallWillBeOrWasMade = 990.
19:10:11.2086 - User action 7: timeToWaitBeforeThisCallShouldBeMade = 1990.
19:10:11.2186 - User action 8: timeUntilPreviousCallWillBeOrWasMade = 990.
19:10:11.2196 - User action 8: timeToWaitBeforeThisCallShouldBeMade = 1990.
19:10:11.2296 - User action 9: timeUntilPreviousCallWillBeOrWasMade = 990.
19:10:11.2296 - User action 9: timeToWaitBeforeThisCallShouldBeMade = 1990.
19:10:11.2406 - User action 10: timeUntilPreviousCallWillBeOrWasMade = 990.
19:10:11.2406 - User action 10: timeToWaitBeforeThisCallShouldBeMade = 1990.
19:10:13.1567 - User action 2: web service call.
19:10:13.1717 - User action 3: web service call.
19:10:13.1877 - User action 5: web service call.
19:10:13.1877 - User action 4: web service call.
19:10:13.2107 - User action 6: web service call.
19:10:13.2187 - User action 7: web service call.
19:10:13.2187 - User action 8: web service call.
19:10:13.2357 - User action 9: web service call.
19:10:13.2537 - User action 10: web service call.

你真的应该为工作使用正确的工具。SemaphoreSlim怎么样?

using System;
using System.Threading;
using System.Threading.Tasks;
namespace ThrottledAsync
{
    class Program
    {
        static void Main(string[] args)
        {
            // Queue up simultaneous calls.
            MakeThrottledCall();
            MakeThrottledCall();
            MakeThrottledCall();
            MakeThrottledCall();
            Console.ReadLine();
        }
        // Used to throttle our web service calls.
        // Max degree of parallelism: 1.
        private static readonly SemaphoreSlim WebServiceMutex = new SemaphoreSlim(1, 1);
        private static async void MakeThrottledCall()
        {
            // Wait for the previous call
            // (and delay task) to complete.
            await WebServiceMutex.WaitAsync();
            try
            {
                await MakeCallToWebService();
                // Report the completion of your web service call if necessary.
                // Delay for a bit before releasing the semaphore.
                await Task.Delay(1000);
            }
            finally
            {
                // Allow the next web service call to go through.
                WebServiceMutex.Release();
            }
        }
        private static async Task MakeCallToWebService()
        {
            // Simulate network delay.
            await Task.Delay(new Random().Next(5, 10));
            Console.WriteLine("WebServiceCall: {0:HH:mm:ss.ffff}", DateTime.Now);
        }
    }
}

编辑:MakeThrottledCall不再返回Task根据svick的评论

可以在msdn上使用Thread.Sleep(msecondtimeout)吗?

我建议你这样做