我有一个要求,我可以在一秒钟内访问 API 5 次。如果我必须发出总共 50 个请求,我想发出前 5 个请求并等待 1 秒,然后我可以用另一批 5 个请求访问 API。我尝试使用线程池以及并行任务库 For\Foreach 循环和任务类,但我无法获得一个顺序计数器来告诉我已经创建了 5 个任务。 这是我正在尝试做的示例:
List<string> str = new List<string>();
for (int i = 0; i <= 100; i++)
{
str.Add(i.ToString());
}
Parallel.ForEach(str, new ParallelOptions { MaxDegreeOfParallelism = 5 },
(value, pls, index) =>
{
Console.WriteLine(value);// simulating method call
if (index + 1 == 5)
{
// need the main thread to sleep so next batch is
Thread.Sleep(1000);
}
});
最佳答案
由于您使用的是 .NET 4.0(并且希望您至少使用 VS2012),您可以使用 Microsoft.Bcl.Async
获得 async-await
特性。
一旦你这样做,你就可以轻松地异步查询你的 API 端点(不需要额外的线程),并使用 AsyncSemaphore
(见下面的实现)来限制你做的请求数量同时。
例如:
public readonly AsyncSemaphore = new AsyncSemaphore(5);
public readonly HttpClient httpClient = new HttpClient();
public async Task<string> LimitedQueryAsync(string url)
{
await semaphoreSlim.WaitAsync();
try
{
var response = await httpClient.GetAsync(url);
return response.Content.ReadAsStringAsync();
}
finally
{
semaphoreSlim.Release();
}
}
现在你可以这样查询了:
public async Task DoQueryStuffAsync()
{
while (someCondition)
{
var results = await LimitedQueryAsync(url);
// do stuff with results
await Task.Delay(1000);
}
}
编辑:
正如@ScottChamberlain 正确指出的那样,SemaphoreSlim
在 .NET 4 中不可用。您可以改为使用 AsyncSemaphore
,如下所示:
public class AsyncSemaphore
{
private readonly static Task s_completed = Task.FromResult(true);
private readonly Queue<TaskCompletionSource<bool>> m_waiters =
new Queue<TaskCompletionSource<bool>>();
private int m_currentCount;
public AsyncSemaphore(int initialCount)
{
if (initialCount < 0)
{
throw new ArgumentOutOfRangeException("initialCount");
}
m_currentCount = initialCount;
}
public Task WaitAsync()
{
lock (m_waiters)
{
if (m_currentCount > 0)
{
--m_currentCount;
return s_completed;
}
else
{
var waiter = new TaskCompletionSource<bool>();
m_waiters.Enqueue(waiter);
return waiter.Task;
}
}
}
public void Release()
{
TaskCompletionSource<bool> toRelease = null;
lock (m_waiters)
{
if (m_waiters.Count > 0)
toRelease = m_waiters.Dequeue();
else
++m_currentCount;
}
if (toRelease != null)
toRelease.SetResult(true);
}
}
关于c# - 创建特定数量的任务\线程后如何等待特定时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32695074/