简体   繁体   中英

Limit number of parallel running methods

In my class I have a download function. Now in order to not allow a too high number of concurrent downloads, I would like to block this function until a "download-spot" is free ;)

void Download(Uri uri)
{
    currentDownloads++;

    if (currentDownloads > MAX_DOWNLOADS)
    {
        //wait here
    }

    DoActualDownload(uri); // blocks long time

    currentDownloads--;
}

Is there a ready made programming pattern for this in C# / .NET?

edit: unfortunatelyt i cant use features from .net4.5 but only .net4.0

May be this

var parallelOptions = new ParallelOptions
{        
    MaxDegreeOfParallelism = 3
};

Parallel.ForEach(downloadUri, parallelOptions, (uri, state, index) =>
{
    YourDownLoad(uri);
});

您应该使用Semaphore来解决此并发问题,请参阅文档中的更多内容: https//msdn.microsoft.com/en-us/library/system.threading.semaphore(v = vs.110).aspx

For such cases, I create an own Queue<MyQuery> in a custom class like QueryManager , with some methods :

  1. Each new query is enqueued in Queue<MyQuery> queries
  2. After each "enqueue" AND in each query answer, I call checkIfQueryCouldBeSent()
  3. The checkIfQueryCouldBeSent() method checks your conditions : number of concomitant queries, and so on. In your case you accept to launch a new query if global counter is less than 5. And you increment the counter
  4. Decrement the counter in query answer

It works only if all your queries are asynchronous. You have to store Callback in MyQuery class, and call it when query is over.

You're doing async IO bound work, there's no need to be using multiple threads with a call such as Parallel.ForEach .

You can simply use naturally async API's exposed in the BCL, such ones that make HTTP calls using HttpClient . Then, you can throttle your connections using SemaphoreSlim and it's WaitAsync method which asynchronously waits:

private readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(3);
public async Task DownloadAsync(Uri uri)
{
    await semaphoreSlim.WaitAsync();
    try
    {
        string result = await DoActualDownloadAsync(uri);
    }
    finally
    {
        semaphoreSlim.Release();
    }
}

And your DoActualyDownloadAsync will use HttpClient to do it's work. Something along the lines of:

public Task<string> DoActualDownloadAsync(Uri uri)
{
    var httpClient = new HttpClient();
    return httpClient.GetStringAsync(uri);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM