c# - 创建特定数量的任务\线程后如何等待特定时间?

标签 c# multithreading parallel-processing

我有一个要求,我可以在一秒钟内访问 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/

相关文章:

c# - 有没有办法检查 C# 中特定值的类属性

c# - 如何监控Azure云服务辅助角色-PAAS上的本地存储磁盘空间

c# - 在没有 'cycles' 的情况下按程序生成迷宫

bash gnu 并行帮助

c# - 在被动 View 中实现事件的好方法是什么?

c# - Thread.Abort() 是如何工作的?

asp.net 使用多线程更新 UI

c# - 只要窗体处于事件状态,如何运行后台线程?

c++ - 如何在 C++ 中传递 STL 对象的消息,例如 MPI 中的 std::map?

c++ - 使用 OpenMP 并行化 c++ Monte Carlo Integration 的最佳方法是什么?