Have a set of Tasks with only X running at a time
SemaphoreSlim maxThread = new SemaphoreSlim(10);
for (int i = 0; i < 115; i++)
{
maxThread.Wait();
Task.Factory.StartNew(() =>
{
//Your Works
}
, TaskCreationOptions.LongRunning)
.ContinueWith( (task) => maxThread.Release() );
}
Run multiple asynchronous Tasks continuously
What I would like is that anytime a task is completed, a new one is started.
This is a perfect use case for SemaphoreSlim
:
private readonly SemaphoreSlim _mutex = new SemaphoreSlim(10);
public async Task AddTask(Func<Task> work)
{
await _mutex.WaitAsync();
try { await work(); }
finally { _mutex.Release(); }
}
A timeout would be great as well, to prevent a task from being run undefinitely in case of a failure.
The standard pattern for timeouts is to use a CancellationTokenSource
as the timer and pass a CancellationToken
into the work that needs to support cancellation:
private readonly SemaphoreSlim _mutex = new SemaphoreSlim(10);
public async Task AddTask(Func<CancellationToken, Task> work)
{
await _mutex.WaitAsync();
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
try { await work(cts.Token); }
finally { _mutex.Release(); }
}
Run Async every x number of times in a for loop
Running tasks in "batch" is not a good idea in terms of performance. A long running task would make whole batch block. A better approach would be starting a new task as soon as one is finished.
This can be implemented with a queue as @MertAkcakaya suggested. But I will post another alternative based on my other answer Have a set of Tasks with only X running at a time
int maxTread = 3;
System.Net.ServicePointManager.DefaultConnectionLimit = 50; //Set this once to a max value in your app
var urls = new Tuple<string, string>[] {
Tuple.Create("http://cnn.com","temp/cnn1.htm"),
Tuple.Create("http://cnn.com","temp/cnn2.htm"),
Tuple.Create("http://bbc.com","temp/bbc1.htm"),
Tuple.Create("http://bbc.com","temp/bbc2.htm"),
Tuple.Create("http://stackoverflow.com","temp/stackoverflow.htm"),
Tuple.Create("http://google.com","temp/google1.htm"),
Tuple.Create("http://google.com","temp/google2.htm"),
};
DownloadParallel(urls, maxTread);
async Task DownloadParallel(IEnumerable<Tuple<string,string>> urls, int maxThreads)
{
SemaphoreSlim maxThread = new SemaphoreSlim(maxThreads);
var client = new HttpClient();
foreach(var url in urls)
{
await maxThread.WaitAsync();
DownloadFile(client, url.Item1, url.Item2)
.ContinueWith((task) => maxThread.Release() );
}
}
async Task DownloadFile(HttpClient client, string url, string fileName)
{
var stream = await client.GetStreamAsync(url);
using (var fileStream = File.Create(fileName))
{
await stream.CopyToAsync(fileStream);
}
}
PS: DownloadParallel will return as soon as it starts the last download. So don't await it. If you really want to await it you should add for (int i = 0; i < maxThreads; i++) await maxThread.WaitAsync();
at the end of the method.
PS2: Don't forget to add exception handling to DownloadFile
C# Task thread pool - Running 100 tasks across only 10 threads
I think you're missing the point by focusing on threads, especially for asynchronous operations that don't require threads to execute.
.NET has a great ThreadPool
you can use. You don't know how many threads are in it and you don't care. It just works (until it doesn't and you need to configure it yourself, but that's very advance).
Running tasks on the ThreadPool
is very simple. Either create a task for each operation and throttle them using a SemaphoreSlim
or use the ready-made TPL Dataflow blocks. For example:
var block = new ActionBlock<SomeData>(
_ => _repository.WriteDataAsync(_), // What to do on each item
new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 10 }); // How many items at the same time
foreach (var item in items)
{
block.Post(item); // Post all items to the block
}
block.Complete(); // Signal completion
await block.Completion; // Asynchronously wait for completion.
If, however, you do plan on creating "dedicated" threads you can use Task.Factory.StartNew
with the LongRunning
option that creates a dedicated thread outside the ThreadPool
. But keep in mind that async operations don't maintain the same thread throughout the operation as async operations don't need a thread. So starting on a dedicated thread may be pointless (more on that on my blog: LongRunning Is Useless For Task.Run With async-await)
Awaiting multiple Tasks with different results
After you use WhenAll
, you can pull the results out individually with await
:
var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();
await Task.WhenAll(catTask, houseTask, carTask);
var cat = await catTask;
var house = await houseTask;
var car = await carTask;
You can also use Task.Result
(since you know by this point they have all completed successfully). However, I recommend using await
because it's clearly correct, while Result
can cause problems in other scenarios.
Can I run multiple slow processes in the background so more than one task can run in parallel?
Convert the list to a list of "Upload" tasks, and await them all with Task.WhenAll()
:
public async Task Run()
{
// This gets populated after calling the web-API and parsing out the result
List<Stream> files = new List<MemoryStream>{.....};
var tasks = files.Select(Upload);
await Task.WhenAll(tasks);
}
See this post for some more information about tasks/await.
Run a task every x-minutes with Windows Task Scheduler
The task must be configured in two steps.
First you create a simple task that start at 0:00, every day. Then, you go in Advanced...
(or similar depending on the operating system you are on) and select the Repeat every X minutes
option for 24 hours.
The key here is to find the advanced properties. If you are using the XP wizard, it will only offer you to launch the advanced dialog once you created the task.
On more recent versions of Windows (7+ I think?):
- Double click the task and a property window will show up.
- Click the
Triggers
tab. - Double click the trigger details and the Edit Trigger window will show up.
- Under
Advanced settings
panel, tickRepeat task every
xxx minutes, and setIndefinitely
if you need. - Finally, click ok.
Related Topics
Multiple Cases in Switch Statement
Casting a Variable Using a Type Variable
Type or Namespace Name Does Not Exist
Converting a Base 64 String to an Image and Saving It
Interprocess Communication for Windows in C# (.Net 2.0)
Calling a Method Every X Minutes
How to Read the Color of a Screen Pixel
C# Open a New Form Then Close the Current Form
How to Make an Event in the Usercontrol and Have It Handled in the Main Form
Wcf Named Pipe Minimal Example
Workaround for Lack of 'Nameof' Operator in C# for Type-Safe Databinding
Loop Through All the Resources in a .Resx File
Mvc3 Dropdownlistfor - a Simple Example
Is Everything in .Net an Object