当另一个请求已经在等待时,当一个请求排队时,您的问题似乎就会发生。这是我对您的伪代码的看法:
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 的评论返回。