While debugging the problem, I minimized the code to the one below to understand why I have the problem. The program is a console application.
The code simply creates an instance of a third-party class and subscribes to an event that does nothing. When I run the code as is:
Line (9) is never executed unless the terminal window loses focus or I press the Enter key multiple times. It's like it's stuck on the line (8). If I replace the line (8) with any other method from ThridParty, such as obj.MethodX() I get the same problem.
If I delete line (8), then I won't have this problem.
If I remove Task.Run (line 5) and let the code on lines (7-9) run outside of Task.Run, then I won't have this problem.
If I uncomment lines 24-25 and 32-33 then I won't have this problem.
I looked at the ThirdParty constructor through dotPeek. It has a few lazy initializations (Lazy<>) of some pluggins and services. So it's likely that calling any obj.MethodX() initializes those plugins and services first. But I still don't understand why it matters if lines 7-9 and 22-34 run on separate threads. It seems as if one of them is starving.
1. class MyService
2. {
3. public void Start()
4. {
5. Task.Run(() =>
6. {
7. var obj = new ThirdParty();
8. obj.ItemChanged += (...) => {};
9. Console.WriteLine("Instantiated ThirdParty");
10. });
11. }
12. }
13. internal class Program
14. {
15. static async Task Main(string[] args)
16. {
17. var service = new MyService();
18. service.Start();
19.
20. await Task.Run(() =>
21. {
22. while (true)
23. {
24. // if (Console.KeyAvailable)
25. // {
26. var read = Console.ReadKey(true);
27. if (read.Key == ConsoleKey.X)
28. {
29. service.Stop();
30. return;
31. }
32. // }
33. // Thread.Sleep(100);
34. }
35. });
36. }
37. }
Related
I have multiple instances of same application, that start at the same time and runs for equal time period (almost). Each application uses Tasks for parallel programming within them. Now I want to limit the number of parallel tasks that can run across these application instances. How can I do it? I tried using semaphore. But no luck. Let's say I am running 5 instance of the application. The first instance creates a semaphore and holds it for n seconds. For n seconds, the remaining four instances are waiting, which is fine. But after that n seconds, the first instance exits, disposing the semaphore instance I guess. After that the remaining 4 starts executing in parallel. Please help.
My code would look something like this:
static void Main(string[] args)
{
List<string> itemList = GetItemList();
Semaphore throttler = new Semaphore(2, 2, "MySemaPhore");
foreach (var item in itemList)
{
throttler.WaitOne();
Task.Run(() =>
{
try
{
DoWork(item);
}
finally
{
throttler.Release();
}
});
}
}
There is a mistake in your code:
You should use (0, 2) for the Semaphore constructor.
The first argument 0 means that initially there are 0 resources occupied.
This can be seen from the official documentation page. https://learn.microsoft.com/en-us/dotnet/api/system.threading.semaphore?view=netcore-3.1. Especially the line "_pool = new Semaphore(0, 3);" in the code example. If you want to go deeper into programming, you should start the habit of reading (at least skimming through) the official documentation page of whatever class you are using.
Now this is the corrected code:
static void Main(string[] args)
{
List<string> itemList = GetItemList();
Semaphore throttler = new Semaphore(0, 2, "MySemaPhore");
foreach (var item in itemList)
{
throttler.WaitOne();
Task.Run(() =>
{
try
{
DoWork(item);
}
finally
{
throttler.Release();
}
});
}
}
I have a Windows service, developed in C#, which does some calculation on data at equal intervals of time say 30 mins. It fetches the data from database and calls a method CalcData() which does some business logic calculations.
class Program
{
static void Main(string[] args)
{
try
{
AutoCalExecution ae = new AutoCalExecution();
ae.FetchData();
ae.CalData();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}
class AutoCalExecution
{
public void FetchData()
{
// fetch data from db
}
public void CalData()
{
line1;
line2;
line3;
line4; // this line has som expression which actually does the calculation.
line5;
}
}
I have given the template of the code which I'm using. In CalData(), line4 is where the calculation is happening. The calculation typically takes 10 mins to be done. So line4 is executed for 10mins.
There are some scenarios where the calculation might take more than 10 mins. In that case I want to cancel the execution and go to line5 after certain amount of time, say 15 mins.
To summarize I want to set a timeout time for line4 for 15 mins(which can be configured based in requirement), If it doesn't finish with in 15 mins, it has to stop and come to line5.
public void CalData()
{
line1;
line2;
line3;
if ( set time to 15 mins exceeds){
line4; // this line has some expression which actually does the calculation.
}
else
{
Log (Line4 execution did not complete in stipulated time);
}
line5;
}
How do I set that condition in C#?
Update
This is something I tried:
var task = Task.Run(() => CalData());
if (task.Wait(TimeSpan.FromMinutes(Convert.ToDouble(timeout))))
{
if (task.Result)
{
log.Info("Completed");
}
else
{
log.Error("Not successful");
}
}
But the problem here is I want line5 to get executed in this method if line 4 doesn't finish. Is there a way I can write this similar code for a piece of code/snippet, instead of whole method?
Make line4 into a task.
Make the task cancellable by a cancellation token.
Use a cancellation token which cancels itself after 10mins (configured time).
https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource.cancelafter?view=netframework-4.8
https://binary-studio.com/2015/10/23/task-cancellation-in-c-and-things-you-should-know-about-it/
I think you want something like this:
var work = Task.Run(() => line4);
if (work.Wait(TimeSpan.FromMinutes(10)))
{
// Work completed within the timeout
}
else
{
// Work did not complete within the timeout
}
Note that this will not actually stop the 'DoWork' code from running, it will continue on a worker thread until it is done. Also note that using 'Wait' risks deadlocks if used improperly, see Don't Block on Async Code.
If you actually want to cancel the processing you should give DoWork a cancellationToken and make the processing abort when the token is cancelled. There are also solutions to abort a running thread, but this is not recommended.
I want to run 3 tasks parallel which will take input form one array of size n in a for loop. Once one task is completed it will take another input from the array and so on.
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int []Arr ={1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List<Task> tasks = new List<Task>();
int maxConcurrency = 5;
using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency))
{
foreach (var x in Arr)
{
concurrencySemaphore.Wait();
var t = Task.Run(async() =>
{
try
{
await concurrencySemaphore.WaitAsync();
print(x);
}
finally
{
concurrencySemaphore.Release();
}
});
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine("Thread {0} count {1}", t.Id, number);
tasks.Add(t);
}
Task.WaitAll(tasks.ToArray());
}
Console.ReadLine();
}
static void print(int x)
{
Console.WriteLine("Hello World! {0}", x);
}
}
}
I expect the output should be hello world! 1-10 but the actual output is
Hello World! 1
Thread 2 count 12
Hello World! 2
Thread 4 count 12
Hello World! 3
Thread 6 count 12
Hello World! 4
Thread 8 count 12
Thread 10 count 12
If you have any other suggestion then you are welcome.
The problem with your code is that you have two wait statements, one blocking and one non-blocking.
concurrencySemaphore.Wait();
await concurrencySemaphore.WaitAsync();
You only need to wait once for an available semaphore. So If you comment out the concurrencySemaphore.Wait() line, your code will work as expected.
Other things to note about your code:
Since you only designated one method for asynchronous processing (the WaitAsync method), this code will run exactly the same if you replace WaitAsync with Wait. So, when using WaitAsync in this situation, the task will first execute the WaitAsync method, if it cannot enter a semaphore, it will put that statement on hold and execute another async statement. But since there are no more async methods defined, the code will just end up blocking until it can enter a semaphore.
To prove your code is processing 5 Tasks at a time, you should add a call to the Sleep method in your PRINT function. This will allow you to visually see the number of Tasks being process at any given time.
Example:
static void print(int x)
{
Console.WriteLine("Hello World! {0}", x);
Thread.Sleep(3000); //Wait 3 seconds to allow other Task to process before exiting
}
To demonstrate here is a tweak version of your code with the Async/Await statements replace with Wait.
class Program
{
static void Main(string[] args)
{
int[] Arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int maxConcurrency = 5;
List<Task> tasks = new List<Task>();
using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(0, maxConcurrency))
{
// Create a Task object for each element in the array
foreach (var x in Arr)
{
tasks.Add(Task.Run(() =>
{
// Block until the task can enter a semaphore
concurrencySemaphore.Wait();
// Do some work
print(x);
// Signal you are done with the semaphore
concurrencySemaphore.Release();
}
));
}
// Wait a haft a second to allow all tasks to start and block.
Thread.Sleep(500);
// This will release "maxConcurrency" tasks to be process at a given time.
concurrencySemaphore.Release(maxConcurrency);
// Main thread waits for all tasks to complete.
Task.WaitAll(tasks.ToArray());
}
Console.WriteLine("Press any key to exit program...."); Console.ReadKey();
} /* end Main */
static void print(int x)
{
Console.WriteLine("Hello World! {0}", x);
Thread.Sleep(3000); //Wait 3 seconds to allow other Task to process before exiting
}
} /* end class */
The results will be similar to what is shown below:
Hello World! 2
Hello World! 4
Hello World! 5
Hello World! 1
Hello World! 6
-- A 3 second pause --
Hello World! 8
Hello World! 9
Hello World! 3
Hello World! 10
Hello World! 7
-- A 3 second pause --
Press any key to exit program....
-- Update --
As mention by Nick, you can also use the Parallel.ForEach method to accomplish the same thing.
Example:
Parallel.ForEach (Arr,
new ParallelOptions { MaxDegreeOfParallelism = maxConcurrency },
(x) => { print(x); } );
Alternatively, you can use Parallel class and specify MaxDegreeOfParallelism. However, just like the documentation says, normally you will not want to do that. See the remarks in the second link.
I wrote a little program to test using BufferBlock (System.Threading.Tasks.Dataflow) to implement a dual-priority consumer-producer queue.
The consumer should always use any items from the high-priority queue first.
In this initial test, I have the producer running at a much slower rate than the consumer, so the data should just come out in the same order it went in, regardless of priority.
However, I find that the result of Task.WhenAny() is not completing until there is something in both queues (or there's a completion), thus acting like Task.WhenAll().
I thought I understood async/await, and I've perused Cleary's "Concurrency in C# Cookbook." However, there is something going on that I'm not understanding.
Any ideas?
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow; // add nuget package, 4.8.0
using static System.Console;
namespace DualBufferBlockExample { // .Net Framework 4.6.1
class Program {
private static async Task Produce(BufferBlock<int> queueLo, BufferBlock<int> queueHi, IEnumerable<int> values) {
await Task.Delay(10);
foreach(var value in values) {
if(value == 3 || value == 7)
await queueHi.SendAsync(value);
else
await queueLo.SendAsync(value);
WriteLine($"Produced {value} qL.Cnt={queueLo.Count} qH.Cnt={queueHi.Count}");
await Task.Delay(1000); // production lag
}
queueLo.Complete();
queueHi.Complete();
}
private static async Task<IEnumerable<int>> Consume(BufferBlock<int> queueLo, BufferBlock<int> queueHi) {
var results = new List<int>();
while(true) {
int value = -1;
while(queueLo.Count > 0 || queueHi.Count > 0) { // take from hi-priority first
if(queueHi.TryReceive(out value) ||
queueLo.TryReceive(out value)) { // process value
results.Add(value);
WriteLine($" Consumed {value}");
await Task.Delay(100); // consumer processing time shorter than production
}
}
var hasNorm = queueHi.OutputAvailableAsync();
var hasLow = queueLo.OutputAvailableAsync();
var anyT = await Task.WhenAny(hasNorm, hasLow); // <<<<<<<<<< behaves like WhenAll
WriteLine($" WhenAny {anyT.Result} qL.Result={hasLow.Result} qH.Result={hasNorm.Result} qL.Count={queueLo.Count} qH.Count={queueHi.Count}");
if(!anyT.Result)
break; // both queues are empty & complete
}
return results;
}
static async Task TestDataFlow() {
var queueLo = new BufferBlock<int>();
var queueHi = new BufferBlock<int>();
// Start the producer and consumer.
var consumer = Consume(queueLo, queueHi);
WriteLine("Consumer Started");
var producer = Produce(queueLo, queueHi, Enumerable.Range(0, 10));
WriteLine("Producer Started");
// Wait for everything to complete.
await Task.WhenAll(producer, consumer, queueLo.Completion, queueHi.Completion);
// show consumer's output
var results = await consumer;
Write("Results:");
foreach(var x in results)
Write($" {x}");
WriteLine();
}
static void Main(string[] args) {
try {
TestDataFlow().Wait();
} catch(Exception ex) {
WriteLine($"TestDataFlow exception: {ex.ToString()}");
}
ReadLine();
}
}
}
Output:
Consumer Started
Producer Started
Produced 0 qL.Cnt=1 qH.Cnt=0
Produced 1 qL.Cnt=2 qH.Cnt=0
Produced 2 qL.Cnt=3 qH.Cnt=0
Produced 3 qL.Cnt=3 qH.Cnt=1
WhenAny True qL.Result=True qH.Result=True qL.Count=3 qH.Count=1
Consumed 3
Consumed 0
Consumed 1
Consumed 2
Produced 4 qL.Cnt=1 qH.Cnt=0
Produced 5 qL.Cnt=2 qH.Cnt=0
Produced 6 qL.Cnt=3 qH.Cnt=0
Produced 7 qL.Cnt=3 qH.Cnt=1
WhenAny True qL.Result=True qH.Result=True qL.Count=3 qH.Count=1
Consumed 7
Consumed 4
Consumed 5
Consumed 6
Produced 8 qL.Cnt=1 qH.Cnt=0
Produced 9 qL.Cnt=2 qH.Cnt=0
WhenAny True qL.Result=True qH.Result=False qL.Count=2 qH.Count=0
Consumed 8
Consumed 9
WhenAny False qL.Result=False qH.Result=False qL.Count=0 qH.Count=0
Results: 3 0 1 2 7 4 5 6 8 9
After calling WhenAny your immediately blocking on both tasks using .Result without knowing that they're both complete.
var anyT = await Task.WhenAny(hasNorm, hasLow);
//This line blocks on both the hasNorm and hasLow tasks preventing execution from continuing.
WriteLine($" WhenAny {anyT.Result} qL.Result={hasLow.Result} qH.Result={hasNorm.Result} qL.Count={queueLo.Count} qH.Count={queueHi.Count}");
awaiting both tasks will also give you the same behavior. The best you can do is await the task returned from WhenAny and only print the results from the completed task.
Additionally, a priority queue is not something that TPL-Dataflow does well out of the box. It treats all messages equally so you end plugging in your own priority implementation. That said you can make it work.
I am playing a little bit with ConfigureAwait because I would like to understand how it works.
Therfore, I wrote the following small console application (actually running in LINQPad):
void Main()
{
// Use dispatcher to execute the code on STA thread
Dispatcher.CurrentDispatcher.Invoke(() => Run());
}
private async static Task Run()
{
var continueOnCapturedContext1 = true;
var continueOnCapturedContext2 = true;
PrintThreadID();
await Task.Run(() => PrintThreadID()).ConfigureAwait(continueOnCapturedContext1);
PrintThreadID();
await Task.Run(() => PrintThreadID()).ConfigureAwait(continueOnCapturedContext2);
PrintThreadID();
}
private static void PrintThreadID()
{
Console.Write(Thread.CurrentThread.ManagedThreadId.ToString("00") + "\t");
}
And I got the following output:
A) true/true
var continueOnCapturedContext1 = true;
var continueOnCapturedContext2 = true;
1) 11 19 11 07 11
2) 11 09 11 12 11
3) 11 06 11 06 11
Expected: dispatcher thread (11) was captured and awaitable tasks were executed on different or same threadpool threads.
B) false/false
var continueOnCapturedContext1 = false;
var continueOnCapturedContext2 = false;
1) 11 23 23 22 22
2) 11 19 19 19 19
3) 11 10 10 10 10
Also expected: SynchronizationContext was not captured, so subsequent awaitable and non-awaitable code were run on threadpool thread (usually the same).
C) false/true
var continueOnCapturedContext1 = false;
var continueOnCapturedContext2 = true;
1) 11 14 14 06 06
2) 11 20 20 20 20
3) 11 17 17 08 08
The result of output 1 and 3 is strange. The 2. awaitbale task was executed with option "continue on captured context" so I would expect that it runs on the same thread as the code that called it.
It seems, that ConfigureAwait(true/false) has no effect on subsequent awaitable calls if it was alreay called before, right?
The 2. awaitbale task was executed with option "continue on captured context" so I would expect that it runs on the same thread as the code that called it.
That assumes that "context == thread", but it doesn't. The synchronization context that uses the thread-pool will resume on any thread in the thread-pool. Now if you don't capture the synchronization context, you'll still end up on "a thread in the thread pool".
So yes, if you're already on a thread-pool thread, it won't matter whether or not you capture the synchronization context... the continuation will still end up on a thread pool thread. But it's worth pointing out that it would be entirely reasonable to have a different synchronization context with multiple threads, and capturing the synchronization context would return to one of those threads, but not necessarily the same one.
It seems, that ConfigureAwait(true/false) has no effect on subsequent awaitable calls if it was already called before, right?
Not quite. That will be the case if the task needs to use the continuation. If the first task you call ConfigureAwait on has already completed, the code will continue to execute synchronously - so at that point, the second ConfigureAwait is important.
Example:
using System;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;
class Test
{
static void Main()
{
var form = new Form();
form.Load += async (sender, args) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.FromResult(10).ConfigureAwait(false);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000).ConfigureAwait(false);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
};
Application.Run(form);
}
}
Sample output:
1
1
5
So the second Console.WriteLine showed that the code was still running on the same thread despite the ConfigureAwait(false), because Task.FromResult returns an already-completed task.