why does the method AwakeTest take 3 seconds instead of one
public static async void AwakeTest()
{
var Do1 = Sleep(1, 1);
var Do2 = Sleep(1, 2);
var Do3 = Sleep(1, 3);
await System.Threading.Tasks.Task.WhenAll(Do1, Do2, Do3);
Console.WriteLine(await Do1);
Console.WriteLine(await Do2);
Console.WriteLine(await Do3);
}
private static async System.Threading.Tasks.Task<int> Sleep(int Seconds, int ID)
{
if (Seconds < 0)
{
throw new Exception();
}
System.Threading.Thread.Sleep(Seconds * 1000);
return ID;
}
Since Thread.Sleep sleeps the thread, and each Task doesn't require to run in a separate thread, it hangs the entire thread.
You should use Task.Delay instead:
await Task.Delay(Seconds * 1000);
Related
we are running an ASP.NET 6 webapplication and are having strange issues with deadlocks.
The app suddenly freezes after some weeks of operations and it seems that it might be caused by our locking mechanism with the SemaphoreSlim class.
I tried to reproduce the issue with a simple test-project and found something strange.
The following code is simply starting 1000 tasks where each is doing some work (requesting semaphore-handle, waiting for 10 ms and releasing the semaphore).
I expected this code to simply execute one task after another. But it freezes because of a deadlock in the first call of the DoWork method (at await Task.Delay(10)).
Does anyone know why this causes a deadlock? I tried exactly the same code with ThreadPool.QueueUserWorkItem instead of Task.Run and Thread.Sleep instead of Task.Delay and this worked as expected. But as soon as I use the tasks it stops working.
Here is the complete code-snippet:
internal class Program
{
static int timeoutSec = 60;
static SemaphoreSlim semaphore = new SemaphoreSlim(1);
static int numPerIteration = 1000;
static int iteration = 0;
static int doneCounter = numPerIteration;
static int successCount = 0;
static int failedCount = 0;
static Stopwatch sw = new Stopwatch();
static Random rnd = new Random();
static void Main(string[] args)
{
Task.WaitAll(TestUsingTasks());
}
static async Task TestUsingTasks()
{
while (true)
{
var tasks = new List<Task>();
if (doneCounter >= numPerIteration)
{
doneCounter = 0;
if (iteration >= 1)
{
Log($"+++++ FINISHED TASK ITERATION {iteration} - SUCCESS: {successCount} - FAILURES: {failedCount} - Seconds: {sw.Elapsed.TotalSeconds:F1}", ConsoleColor.Magenta);
}
iteration++;
sw.Restart();
for (int i = 0; i < numPerIteration; i++)
{
// Start indepdent tasks to do some work
Task.Run(async () =>
{
if (await DoWork())
{
successCount++;
}
else
{
failedCount++;
}
doneCounter++;
});
}
}
await Task.Delay(10);
}
}
static async Task<bool> DoWork()
{
if (semaphore.Wait(timeoutSec * 1000)) // Request the semaphore to ensure that one 1 task at a time can enter
{
Log($"Got handle for {iteration} within {sw.Elapsed.TotalSeconds:F1}", ConsoleColor.Green);
var totalSec = sw.Elapsed.TotalSeconds;
await Task.Delay(10); // Wait for 10ms to simulate some work => Deadlock seems to happen here
Log($"RELEASING LOCK handle for {iteration} within {sw.Elapsed.TotalSeconds:F1}. WAIT took " + (sw.Elapsed.TotalSeconds - totalSec) + " seconds", ConsoleColor.Gray);
semaphore.Release();
return true;
}
else
{
Log($"ERROR: TASK handle failed for {iteration} within {sw.Elapsed.TotalSeconds:F1} sec", ConsoleColor.Red);
return false;
}
}
static void Log(string message, ConsoleColor color)
{
Console.ForegroundColor = color;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.White;
}
}
Thanks in advance!
But it freezes because of a deadlock in the first call of the DoWork method (at await Task.Delay(10)).
I would argue that it is not deadlock but a thread starvation issue. If you wait long enough you will see that threads will be able to finish the simulation wait from time to time.
The quick fix here is using non-blocking WaitAsync call with await:
static async Task<bool> DoWork()
{
if (await semaphore.WaitAsync(timeoutSec * 1000))
{
...
}
}
Also note:
It is recommended to wrap the code after Wait.. into try-finally block and release the semaphore in the finally.
Incrementing counters in parallel environments better should be done in atomic fashion, for example with Interlocked.Increment.
How to cancel all tasks, if one of them return i.e. false (bool) result?
Is it possible to identify which task returned a result?
class Program
{
private static Random _rnd = new Random();
static void Main(string[] args)
{
var tasksCounter = _rnd.Next(4, 7);
var cts = new CancellationTokenSource();
var tasks = new Task<bool>[tasksCounter];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = CreateTask(cts);
}
Console.WriteLine("Waiting..");
Task.WaitAny(tasks);
Console.WriteLine("Done!");
Console.ReadKey();
}
private static Task<bool> CreateTask(CancellationTokenSource cts)
{
return Task.Factory.StartNew(TaskAction, cts.Token).Unwrap();
}
private static async Task<bool> TaskAction()
{
var delay = _rnd.Next(2, 5);
await Task.Delay(delay * 1000);
var taskResult = _rnd.Next(10) < 4;
return await Task.FromResult(taskResult);
}
}
I tried to use Task.WaitAll, Task.WaitAny etc, but none of these methods provide useful (in my case) functionality.
Edit:
As #ckuri stated in the comments, it would be easier to leverage the already existing properties of Task instead of writing a custom result class. Adjusted my answer accordingly.
One solution would be to check for the result in the CreateTask() method and pass a CancellationToken into your TaskAction() method:
private static Task<bool> CreateTask(CancellationTokenSource cts)
{
return Task.Run(async () =>
{
var result = await TaskAction(cts.Token);
// If result is false, cancel all tasks
if (!result)
cts.Cancel();
return result;
});
}
private static async Task<bool> TaskAction(CancellationToken token)
{
// Check for cancellation
token.ThrowIfCancellationRequested();
var delay = Rnd.Next(2, 5);
// Pass the cancellation token to Task.Delay()
await Task.Delay(delay * 1000, token);
var taskResult = Rnd.Next(10) < 4;
// Check for cancellation
token.ThrowIfCancellationRequested();
return taskResult;
}
Now you can do something like this in your Main method to receive all tasks which did not get cancelled:
try
{
// Wait for all tasks inside a try catch block because `WhenAll` throws a `AggregationException`
// containing a `TaskCanceledException`, if the token gets canceled
await Task.WhenAll(tasks);
}
catch { }
var tasksWithResult = tasks.Where(t => !t.IsCanceled).ToList();
I don't have an interpreter on hand, so excuse any mistakes. Your Task needs access to the token if you want to cancel all tasks from the task itself. See https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource?view=netcore-3.0 for an example. I.e. pass it as an argument to the task so one task can cancel the other tasks.
private static async Task<bool> TaskAction(CancellationTokenSource cts)
{
var delay = _rnd.Next(2, 5);
await Task.Delay(delay * 1000);
var taskResult = _rnd.Next(10) < 4;
if (!taskResult)
cts.Cancel()
return await Task.FromResult(taskResult);
}
Just be sure to capture the AggregateException and check if one of the inner excepts is an TaskCanceledException.
I want to do some work with a coded in Delay with the UI active.
I thought I had TaskOfTResult_MethodSync fixed with Task.Delay(delay).Wait();. The problem is that blocks Task<int> taskS = TaskOfTResult_MethodSync(10000); it does not immediately move on to the await and the UI is not responsive. UI does not even paint until after the delay.
public async void TestTask3(int delay, CancellationToken ct) works but it does not let me return a value.
If I use
int rslt = TestTask3(1000, token).Result;
public async Task<int> TestTask3(int delay, CancellationToken ct)
It hangs on int rslt = TestTask3(1000, token).Result;
This is not valid syntax await TestTask3(1000, token);
I don't mind using public async void TestTask3(int delay, CancellationToken ct) but I would rather have work done with programmed Delay or Sleep that returns a value (rather than update a public property from the async method). What I want is to kick off a method / task then do some other work from the main tread. Then await. After the await some buttons get activated.
The reason I need a programmed in delay is it reads some instrument data and it needs to wait between reads to get a sample set.
Is there a way to get what I want?
I currently get what I need with BackGroundWorker but that but I was hoping to get there with task.
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
Debug.WriteLine("before Task<int> taskS = TaskOfTResult_MethodSync(10000);");
Task<int> taskS = TaskOfTResult_MethodSync(10000);
Debug.WriteLine("before taskS.Wait");
taskS.Wait();
Debug.WriteLine("after taskS.Wait");
int i = taskS.Result;
Debug.WriteLine($"i = {i}");
Debug.WriteLine($"");
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
Debug.WriteLine("before TestTask3(1000, token);");
TestTask3(1000, token);
Debug.WriteLine("after TestTask3(1000, token);");
Thread.Sleep(2000);
Debug.WriteLine("after sleep on main TestTask3(1000, token);");
source.Cancel();
Debug.WriteLine("done Main");
}
public async void TestTask3(int delay, CancellationToken ct)
{
Debug.WriteLine($"TestTask3");
int ans = -1;
ans = await Task.Run(async () =>
{
// … do compute-bound work here
for (int j = 101; j <= 120; j++)
{
if(ct.IsCancellationRequested)
{
break;
}
await Task.Delay(delay);
ans = j;
Answer = j;
}
});
Debug.WriteLine($"TestTask3 {ans}");
Answer = ans;
//return ans;
}
Task<int> TaskOfTResult_MethodSync(int delay)
{
Debug.WriteLine($"TaskOfTResult_MethodSync delay = {delay} {DateTime.Now}");
int hours = 10;
Task.Delay(delay).Wait();
Debug.WriteLine($"TaskOfTResult_MethodSync after delay {DateTime.Now}");
return Task.FromResult(hours);
}
It's a bit unclear what you are trying to do here but both Wait() and Result will block synchronously.
You should make the TaskOfTResult_MethodSync method async and await Task.Delay:
async Task<int> TaskOfTResult_MethodSync(int delay)
{
Debug.WriteLine($"TaskOfTResult_MethodSync delay = {delay} {DateTime.Now}");
int hours = 10;
await Task.Delay(delay);
Debug.WriteLine($"TaskOfTResult_MethodSync after delay {DateTime.Now}");
return hours;
}
This makes the method asynchronous method.
Since the constructor is not asynchronous you could then move the invocation of the asynchronous method to a Loaded event handler. And TestTask3 should not return void if you want to be able to await it. Change the return type to Task and await this one also.
Finally, if call Thread.Sleep on the UI thread, your UI will indeed freeze. Use await Task.Delay if you want to "sleep" asynchronously:
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
Loaded += async (s, e) =>
{
Debug.WriteLine("before Task<int> taskS = TaskOfTResult_MethodSync(10000);");
int i = await TaskOfTResult_MethodSync(10000);
Debug.WriteLine($"i = {i}");
Debug.WriteLine($"");
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
Debug.WriteLine("before TestTask3(1000, token);");
await TestTask3(1000, token);
Debug.WriteLine("after TestTask3(1000, token);");
await Task.Delay(2000);
Debug.WriteLine("after sleep on main TestTask3(1000, token);");
source.Cancel();
Debug.WriteLine("done Main");
};
}
public async Task TestTask3(int delay, CancellationToken ct)
{
Debug.WriteLine($"TestTask3");
await Task.Run(async () =>
{
// … do compute-bound work here
for (int j = 101; j <= 120; j++)
{
if (ct.IsCancellationRequested)
{
break;
}
await Task.Delay(delay);
ans = j;
Answer = j;
}
});
Debug.WriteLine($"TestTask3 {ans}");
Answer = ans;
}
One of the first issues that I noted in your code is that you are making all this async calls in your constructor (that's why you can't await TestTask3). I suggest you refer to this question to understand why this is bad.
Now, if you move your code to not be in your constructor, then you don't need to use the blocking constructs (like Wait() and .Result) and use await instead. For example, here is what TaskOfTResult_MethofSync implementation could look like:
private async Task<int> TaskOfTResult_MethodSync(int delay)
{
await Task.Delay(delay);
return Task.FromResult(10);
}
Note how instead of blocking on the .Delay call it now awaits
Working on using the HttpClient to convert WebClient code from .Net Framework 4.6.1 to NetStandard 1.6, and having an odd issue. Here's my code blocks that are in question:
public double TestDownloadSpeed(Server server, int simultaniousDownloads = 2, int retryCount = 2)
{
var testData = GenerateDownloadUrls(server, retryCount);
return TestSpeed(testData, async (client, url) =>
{
var data = await client.GetByteArrayAsync(url);
return data.Length;
}, simultaniousDownloads);
}
public double TestUploadSpeed(Server server, int simultaniousUploads = 2, int retryCount = 2)
{
var testData = GenerateUploadData(retryCount);
return TestSpeed(testData, async (client, uploadData) =>
{
client.PostAsync(server.Url, new StringContent(uploadData.ToString())).RunSynchronously();
return uploadData[0].Length;
}, simultaniousUploads);
}
private static double TestSpeed<T>(IEnumerable<T> testData, Func<HttpClient, T, Task<int>> doWork, int concurencyCount = 2)
{
var timer = new Stopwatch();
var throttler = new SemaphoreSlim(concurencyCount);
timer.Start();
var downloadTasks = testData.Select(async data =>
{
await throttler.WaitAsync().ConfigureAwait(true);
var client = new CoreSpeedWebClient();
try
{
var size = await doWork(client, data).ConfigureAwait(true);
return size;
}
finally
{
client.Dispose();
throttler.Release();
}
}).ToArray();
Task.Run(() => downloadTasks);
timer.Stop();
double totalSize = downloadTasks.Sum(task => task.Result);
return (totalSize * 8 / 1024) / ((double)timer.ElapsedMilliseconds / 1000);
}
So, when calling the TestDownloadSpeed function everything works as expected, but when I call the TestUploadSpeed method I get the error InvalidOperationException: RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.* on this portion of TestSpeed.
double totalSize = downloadTasks.Sum(task => task.Result);
I am really wracking my brain trying to figure out what in TestUploadSpeed is blowing things up. Anyone have any hints to point me in the right direction?
If it helps, here's the .Net 4.6.1 code that works without issue, so maybe something in my translation is off? Plus the original code runs about 5 times faster so not sure what that's about...
public double TestDownloadSpeed(Server server, int simultaniousDownloads = 2, int retryCount = 2)
{
var testData = GenerateDownloadUrls(server, retryCount);
return TestSpeed(testData, async (client, url) =>
{
var data = await client.DownloadDataTaskAsync(url).ConfigureAwait(false);
return data.Length;
}, simultaniousDownloads);
}
public double TestUploadSpeed(Server server, int simultaniousUploads = 2, int retryCount = 2)
{
var testData = GenerateUploadData(retryCount);
return TestSpeed(testData, async (client, uploadData) =>
{
await client.UploadValuesTaskAsync(server.Url, uploadData).ConfigureAwait(false);
return uploadData[0].Length;
}, simultaniousUploads);
}
private static double TestSpeed<T>(IEnumerable<T> testData, Func<WebClient, T, Task<int>> doWork, int concurencyCount = 2)
{
var timer = new Stopwatch();
var throttler = new SemaphoreSlim(concurencyCount);
timer.Start();
var downloadTasks = testData.Select(async data =>
{
await throttler.WaitAsync().ConfigureAwait(false);
var client = new SpeedTestWebClient();
try
{
var size = await doWork(client, data).ConfigureAwait(false);
return size;
}
finally
{
client.Dispose();
throttler.Release();
}
}).ToArray();
Task.WaitAll(downloadTasks);
timer.Stop();
double totalSize = downloadTasks.Sum(task => task.Result);
return (totalSize * 8 / 1024) / ((double)timer.ElapsedMilliseconds / 1000);
}
tl;dr
To fix your specific example, you want to call Wait() to synchronously wait for the Task to complete. Not RunSynchronously().
But you probably actually want to await the Task to allow asynchronous completion. Wait() isn't very good for performance in most cases and has some characteristics that can cause deadlock if used unwisely.
long explanation
RunSynchronously() has a subtly different usage than Wait(). It runs the Task synchronously, while Wait will wait synchronously but doesn't dictate anything about how it should run.
RunSynchronously() it isn't very useful in modern TPL usage. It is meant to be called only on a cold Task -- one that hasn't been started.
The reason this isn't very useful is that just about every library method returning a Task will be returning a hot Task -- one that has already started. This includes the ones from HttpClient. When you call it on a Task that has already been started, you get the exception you've just run into.
I have this "simple" test code... (Don't bother the strange use of the Class methods...)
I am trying to grasp the Task<> intricacies... I think I have a little understanding of Task<>.Start()/Task<>.Result pattern (maybe as it resembles more the 'old' Thread.Start()?) but as soon as it seems to me to grasp something (and so I throw in the await keyword)... then all entangles again :-(
Why my code returns immediately after the first task completes? Why it doesn't wait on the Task.WhenAll()?
static BigInteger Factorial(BigInteger factor)
{
BigInteger factorial = 1;
for (BigInteger i = 1; i <= factor; i++)
{
factorial *= i;
}
return factorial;
}
private class ChancesToWin
{
private int _n, _r;
public ChancesToWin(int n, int r)
{
_n = n;
_r = r;
}
private Task<BigInteger> CalculateFactAsync(int value)
{
return Task.Factory.StartNew<BigInteger>(() => Factorial(value));
}
public async Task<BigInteger> getFactN()
{
BigInteger result = await CalculateFactAsync(_n);
return result;
}
public async Task<BigInteger> getFactN_R()
{
BigInteger result = await CalculateFactAsync(_n - _r);
return result;
}
public async Task<BigInteger> getFactR()
{
BigInteger result = await CalculateFactAsync(_r);
return result;
}
}
private async static void TaskBasedChancesToWin_UseClass()
{
int n = 69000;
int r = 600;
List<Task<BigInteger>> tasks = new List<Task<BigInteger>>();
ChancesToWin ctw = new ChancesToWin(n, r);
tasks.Add(ctw.getFactN());
tasks.Add(ctw.getFactN_R());
tasks.Add(ctw.getFactR());
// The getFactR() returns first of the other two tasks... and the code exit!
BigInteger[] results = await Task.WhenAll(tasks);
// I don't get here !!!!
BigInteger chances = results[0] / results[1] * results[2];
//Debug.WriteLine(chances);
}
static void Main(string[] args)
{
TaskBasedChancesToWin_UseClass();
}
Async methods run synchronously until the first await when they return control to the calling method, usually returning a task representing the rest of the asynchronous operation. TaskBasedChancesToWin_UseClass doesn't return a task so the caller can't wait for it to complete. That's why you shouldn't use async void outside of event handlers.
Since Main doesn't wait for the operation your application ends before the operation had a chance to complete.
You would usually wait with await but since you Main can't be an async method you can block synchronously with Wait on the task returned from TaskBasedChancesToWin_UseClass:
async static Task TaskBasedChancesToWin_UseClass()
{
// ...
}
static void Main()
{
TaskBasedChancesToWin_UseClass().Wait();
}