This question already has an answer here:
Async Await Running Synchronously
(1 answer)
Closed 2 years ago.
Assuming that I need to have some concurrent processes and I would like to forget about the old Thread class and stick to Task with an async pattern. Given the following codes:
// Scenario 1
public async Task Accept() {
while(true) {
Connection con = await connection.AcceptAsync();
await HandleConnection(con);
}
}
public Task HandleConnection(Connection con) {
// Long Running Logic
return Task.CompletedTask;
}
// Scenario 2
public async Task Accept() {
while(true) {
Connection con = await connection.AcceptAsync();
HandleConnection(con); // Produces a warning
}
}
public Task HandleConnection(Connection con) {
// Long Running Logic
return Task.CompletedTask;
}
Both these approaches fail and I cannot handle the connection concurrently. For example when the first connection is accepted then I cannot accept the second connection until the HandleConnection method finishes its job. To solve this problem I can do the following:
public async Task Accept() {
while(true) {
Connection con = await connection.AcceptAsync();
HandleConnection(con); // Produces a warning
}
}
public Task HandleConnection(Connection con) {
return Task.Run(()=> {
//Long Running Logic
});
}
Now I am able to handle multiple connections but this behavior raises a few questions:
1- I heard that the await keyword in contrast with wait is non-blocking and in fact the whole async pattern in non-blocking as well. But in this situation it is actually blocking the parent thread.
2- When a method is async, a Task resembling that method must be generated as a result so that it can be awaited, is that true? if that is true then why is it blocking? else how does the await mechanism work?
3- If I don't await the Task, I get a compile time warning which says I have to await the task, but if I use it then the parent thread is blocked.
To ditch the warning I can do HandleConnection(con).Wait(0) but isn't that a bad practice?
I played with this issue and tested that thoroughly. The conclusion is that in a method that returns a Task, if you do not actually return a Task or instead await or return Task.CompletedTask, that method will still run on the Parent thread and will surely block it. You can only benefit from multithreading if you actually raise a Task as I represented in my question.
To prove this, the following is blocking:
public static void Main(String[] args) {
test();
Console.WriteLine("Hello World");
}
private static Task test() {
while(true) {}
return Task.CompletedTask;
}
In this code test will block the main thread.
If you make the test async, it will still block the main thread.
public static void Main(String[] args) {
test();
Console.WriteLine("Hello World");
}
private static async Task test() {
while(true) {}
}
This is while the following does not block the main thread:
public static async Task test() {
await Task.Run(()=> {
while(true) {}
});
}
However, if you don't want to await the Task you should raise the Task in void method:
public void Method() {
Task.Run(()=> ());
}
This is much better than Task.Wait(0).
Related
I'm trying to create multiple tasks, run them in parallel, and wait for them all to finish.
public class SimulationManager
{
public List<Task> Simulations = new List<Task>();
public void AddSimulation(SimulationParameters parameters)
{
Simulations.Add(new Task(async () => await new Simulation().Simulate()));
}
public async Task StartSimulations()
{
Simulations.ForEach(s => s.Start());
await Task.WhenAll(Simulations);
Console.WriteLine("All tasks finished");
}
}
The task itself delays the execution by one second and then prints out a message.
public class Simulation
{
public async Task Simulate()
{
Console.WriteLine("Simulating");
await Task.Delay(1000);
}
}
I would expect the output to be:
Simulating
All tasks finished
Instead, I get:
All tasks finished
Simulating
If I replace await Task.Delay(1000) with Thread.Sleep(1000) it works as expected.
Why is the task being marked as completed without actually being completed?
If I read the status of the task before and after Task.WhenAll, it is awaiting correctly. The problem is then that Task.Delay is not delaying the execution even though the method is async.
Simulations.ForEach(s => s.Start());
Console.WriteLine(Simulations.First().Status); // prints "WaitingToRun"
await Task.WhenAll(Simulations);
Console.WriteLine(Simulations.First().Status); // prints "RanToCompletion"
Console.WriteLine("All tasks finished");
Remove redundant Task wrapper - this is what causing the issues.
Store simulations as a function returning Task and start simulation explicitly by invoking it.
public class SimulationManager
{
public List<Func<Task>> Simulations = new List<Func<Task>>();
public void AddSimulation(SimulationParameters parameters)
{
Simulations.Add(() => new Simulation().Simulate());
}
public async Task StartSimulations()
{
var tasks = Simulations.Select(simulate => simulate()).ToArray();
await Task.WhenAll(tasks);
Console.WriteLine("All tasks finished");
}
}
You are waiting on the wrong thing. Here is a fixed version
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace TaskSimulateEarlyReturn
{
public class Simulation
{
public async Task Simulate()
{
Console.WriteLine("Simulating");
await Task.Delay(1000);
Console.WriteLine("Finished Simulating");
}
}
public class SimulationManager
{
public List<Task<Task>> Simulations = new List<Task<Task>>();
public void AddSimulation()
{
Simulations.Add(new Task<Task>(async () => await new Simulation().Simulate()));
}
public async Task StartSimulations()
{
for(int i=0;i<4;i++)
{
AddSimulation();
}
Simulations.ForEach(s => s.Start());
await Task.WhenAll(Simulations.Select(x=>x.Unwrap()).ToArray());
Console.WriteLine("All tasks finished");
}
}
class Program
{
static void Main(string[] args)
{
var man = new SimulationManager();
man.StartSimulations().Wait();
Thread.Sleep(1000);
}
}
}
The key ingredient is that you are creating a task with an async method inside it. Implicitely an async method will always return a task which is complete when the async method has completed. Since you are wrapping the Task with a Task you are waiting on the outer unrelated task which completes immediately hence your race condition.
async void F1()
{
await Task.CompletedTask;
}
async Task F2()
{
await Task.CompletedTask;
}
Both async methods are identical but the F1 method which does return void will still return a task under the hood or else you would not be able to await it. This is just a compiler trick to make "old" code work with async methods, without packing async as special method signature on top of it.
You are creating then tasks like this:
var t = new Task(F1);
var t1 = new Task<Task>(F2);
But now you have wrapped the async task returning method inside an outer task which will be complete as soon as the first sync part of the async method has completed.
What you need to do is to wait on the inner task which can be conveniently done with Task.Unwrap which is there exactly for that reason.
If you remove the Task.Unwrap call in my sample you are waiting on the outer task and you are getting your race condition back.
In general I would not use async/await except to free up the UI thread. async/await is inherently single threaded because you can await always only one task. If used this way (Task.WhenAll is kind of cheating) the one and only feature you get is thread hopping. At a single point in time your async await things will run on one thread which might change before during and after the await depending on the Synchronization Contexts.
Calling .Execute() on a ReactiveCommand hangs or creates a deadlock in the example below. Why is this happening, and what is the best way to avoid it?
The error only occurs when Dispatcher.CurrentDispatcher is called. The obvious answer, to not call it, is unfortunately not an option in the larger project.
I have nuget packages reactiveui-core and reactiveui-winforms in the project, both v7.4.0. I'm running nunit tests from Visual Studio with Resharper.
The code is an NUnit test fixture, note the TimeoutAfterAsync is a helper method to cancel the test after a certain timeout, the behaviour is observed without this wrapper
[TestFixture]
public class ReactiveCommandTests
{
private static async Task<bool> ExecuteCommand()
{
await Task.Delay(1000);
return true;
}
public static ReactiveCommand<Unit, bool> Command = ReactiveCommand.CreateFromTask(ExecuteCommand);
public static ReactiveCommand<Unit, bool> CommandOnTaskpoolScheduler = ReactiveCommand.CreateFromTask(ExecuteCommand, outputScheduler: RxApp.TaskpoolScheduler);
public static ReactiveCommand<Unit, bool> CommandAfterDispatcherInvoked = ReactiveCommand.CreateFromTask(ExecuteCommand);
[Test, Order(1)]
public async Task Test()
{
//THIS WORKS
try
{
await TimeoutAfterAsync(
Command.Execute(),
TimeSpan.FromSeconds(5),
"control");
}
catch (TimeoutException)
{
Assert.Fail("Control case timed out (not expected)");
}
}
[Test, Order(2)]
public async Task Test_CreateCommandAfterDispatcherCall()
{
//This line causes unwanted behaviour
var x = Dispatcher.CurrentDispatcher;
//THIS FAILS
try
{
await TimeoutAfterAsync(
CommandAfterDispatcherInvoked.Execute(),
TimeSpan.FromSeconds(5),
"after dispatcher creation");
}
catch (TimeoutException)
{
Assert.Fail("Executing commandAfterDispatcherInvoked timed out (expected, but not understood");
}
}
[Test, Order(3)]
public async Task Test_CreateCommandWithThreadpoolScheduler()
{
//This line causes unwanted behaviour
var x = Dispatcher.CurrentDispatcher;
//THIS WORKS AGAIN (using ThreadpoolScheduler when creating ReactiveCommand)
try
{
await TimeoutAfterAsync(
CommandOnTaskpoolScheduler.Execute(),
TimeSpan.FromSeconds(5),
"after dispatcher creation, with thread pool");
}
catch (TimeoutException)
{
Assert.Fail("ThreadpoolScheduler case timed out (not expected)");
}
}
private static async Task<TResult> TimeoutAfterAsync<TResult>(IObservable<TResult> observable,
TimeSpan timeout,
string context)
{
var task = observable .ToTask();
var result = await Task.WhenAny(task, Task.Delay(timeout));
if (result == task)
{
// Task completed within timeout.
return task.GetAwaiter().GetResult();
}
else
{
// Task timed out.
throw new TimeoutException(context);
}
}
}
Dispatcher.CurrentDispatcher is a fun one; it creates a dispatcher for the current thread if it doesn't already have one! This causes a problem for unit tests, since the new dispatcher is created for a thread pool thread, which isn't STA and doesn't have a message pump.
The ideal solution is to not call CurrentDispatcher. Ever. Use await or IProgress<T> or (if you must) SynchronizationContext to communicate results/progress/events to the UI thread. These abstractions are much easier to create a test environment for.
But for now, you may be able to use WpfContext, an old utility type that was included in early versions of the Async CTP. WpfContext.Run will take a delegate, create a dispatcher context for the current thread, and execute the delegate within that dispatcher context, pumping its messages until the asynchronous operations have completed.
I am looking for a way to "add some context" to my methods for debugging purposes. Even though using StackTrace works fine with sync code, when going async, things naturally stop working. I fully understand why but I can't find a good way to solve this.
[Scope("method 1")]
private async Task Method1()
{
// ... other awaited calls
await DoWork();
}
[Scope("method 2")]
private async Task Method2()
{
// ... other awaited calls
await DoWork();
}
private async Task DoWork()
{
// Get ScopeAttribute from parent method
var description = new StackTrace()
.GetFrames()
?.SelectMany(f => f.GetMethod().GetCustomAttributes(typeof(ScopeAttribute), false))
.Cast<ScopeAttribute>()
.FirstOrDefault()?.Description;
}
How to get to ScopeAttribute decorated on parent methods? In a sync world the above would just work. In an async world, the stack trace is lost. Any ideas?
The solution does not necessarily have to involve using attributes.
If I understand your use-case correctly, what you're looking for is AsyncLocal:
private static AsyncLocal<string> _scope = new AsyncLocal<string>();
private async Task Method1()
{
_scope.Value = "method 1";
// ... other awaited calls
await DoWork();
}
private async Task Method2()
{
_scope.Value = "method 2";
// ... other awaited calls
await DoWork();
}
private async Task DoWork()
{
Console.WriteLine(_scope.Value);
}
I need to do a work in a Task (infinite loop for monitoring) but how can I get the result of this work?
My logic to do this stuff i wrong? This is a scope problem I think.
There is an example simplified:
The variable is "first" and I want "edit"
namespace my{
public class Program{
public static void Main(string[] args){
Logic p = new Logic();
Task t = new Task(p.process);
t.Start();
Console.WriteLine(p.getVar());// result="first"
}
}
public class Logic{
public string test = "first";
public void process(){
while(true){
//If condition here
this.test = "edit";
}
}
public String getVar(){
return this.test;
}
}
}
It can be done using custom event. In your case it can be something like:
public event Action<string> OnValueChanged;
Then attach to it
p.OnValueChanged += (newValue) => Console.WriteLine(newValue);
And do not forget to fire it
this.test = "edit";
OnValueChanged?.Invoke(this.test);
Tasks aren't threads, they don't need a .Start call to start them. All examples and tutorials show the use of Task.Run or Task.StartNew for a reason - tasks are a promise that a function will execute at some point in the future and produce a result. They will run on threads pulled from a ThreadPool when a Task Scheduler decides they should. Creating cold tasks and calling .Start doesn't guarantee they will start, it simply makes the code a lot more difficult to read.
In the simplest case, polling eg a remote HTTP endpoint could be as simple as :
public static async Task Main()
{
var client=new HttpClient(serverUrl);
while(true)
{
var response=await client.GetAsync(relativeServiceUrl);
if(!response.IsSuccessStatusCode)
{
//That was an error, do something with it
}
await Task.Delay(1000);
}
}
There's no need to start a new Task because GetAsync is asynchronous. WCF and ADO.NET also provide asynchronous execution methods.
If there's no asynchronous method to call, or if we need to perform some heavey work before the async call, we can use Task.Run to start a method in parallel and await for it to finish:
public bool CheckThatService(string serviceUrl)
{
....
}
public static async Task Main()
{
var url="...";
//...
while(true)
{
var ok=Task.Run(()=>CheckThatService(url));
if(!ok)
{
//That was an error, do something with it
}
await Task.Delay(1000);
}
}
What if we want to test multiple systems in parallel? We can start multiple tasks in parallel, await all of them to complete and check their results:
public static async Task Main()
{
var urls=new[]{"...","..."};
//...
while(true)
{
var tasks=urls.Select(url=>Task.Run(()=>CheckThatService(url));
var responses=await Task.WhenAll(tasks);
foreach(var response in responses)
{
///Check the value, due something
}
await Task.Delay(1000);
}
}
Task.WhenAll returns an array with the results in the order the tasks were created. This allows checking the index to find the original URL. A better idea would be to return the result and url together, eg using tuples :
public static (bool ok,string url) CheckThatService(string serviceUrl)
{
....
return (true,url);
}
The code wouldn't change a lot:
var tasks=urls.Select(url=>Task.Run(()=>CheckThatService(url));
var responses=await Task.WhenAll(tasks);
foreach(var response in responses.Where(resp=>!resp.ok))
{
///Check the value, due something
}
What if we wanted to store the results from all the calls? We can't use a List or Queue because they aren't thread safe. We can use a ConcurrentQueue instead:
ConcurrentQueue<string> _results=new ConcurrentQueue<string>();
public static (bool ok,string url) CheckThatService(string serviceUrl)
{
....
_results.Enqueue(someresult);
return (true,url);
}
If we want to report progress regularly we can use IProgress<T> as shown in Enabling Progress and Cancellation in Async APIs.
We could put all the monitoring code in a separate method/class that accepts an IProgress< T> parameter with a progress object that can report success, error messages and the URL that caused them, eg :
class MonitorDTO
{
public string Url{get;set;}
public bool Success{get;set;}
public string Message{get;set;}
public MonitorDTO(string ulr,bool success,string msg)
{
//...
}
}
class MyMonitor
{
string[] _urls=url;
public MyMonitor(string[] urls)
{
_urls=url;
}
public Task Run(IProgress<MonitorDTO> progress)
{
while(true)
{
var ok=Task.Run(()=>CheckThatService(url));
if(!ok)
{
_progress.Report(new MonitorDTO(ok,url,"some message");
}
await Task.Delay(1000);
}
}
}
This class could be used in this way:
public static async Task Maim()
{
var ulrs=new[]{....};
var monitor=new MyMonitor(urls);
var progress=new Progress<MonitorDTO>(pg=>{
Console.WriteLine($"{pg.Success} for {pg.Url}: {pg.Message}");
});
await monitor.Run(progress);
}
Enabling Progress and Cancellation in Async APIs shows how to use the CancellationTokenSource to implement another important part of a monitoring class - cancelling it. The monitoring method could check the status of a cancellation token periodically and stop monitoring when it's raised:
public Task Run(IProgress<MonitorDTO> progress,CancellationToken ct)
{
while(!ct.IsCancellationRequested)
{
//...
}
}
public static async Task Maim()
{
var ulrs=new[]{....};
var monitor=new MyMonitor(urls);
var progress=new Progress<MonitorDTO>(pg=>{
Console.WriteLine($"{pg.Success} for {pg.Url}: {pg.Message}");
});
var cts = new CancellationTokenSource();
//Not awaiting yet!
var monitorTask=monitor.Run(progress,cts.Token);
//Keep running until the first keypress
Console.ReadKey();
//Cancel and wait for the monitoring class to gracefully stop
cts.Cancel();
await monitorTask;
In this case the loop will exit when the CancellationToken is raised. By not awaiting on MyMonitor.Run() we can keep working on the main thread until an event occurs that signals monitoring should stop.
The getVar method is executed before the process method.
Make sure that you wait until your task is finished before you call the getVar method.
Logic p = new Logic();
Task t = new Task(p.process);
t.Start();
t.Wait(); // Add this line!
Console.WriteLine(p.getVar());
If you want to learn more about the Wait method, please check this link.
Given the following code:
public async Task Send() // part of Sender class
{
// sync code
}
// //
private async Task HandleMessage()
{
// await sender.Send(); // exits HandleMessage immediately
sender.Send().Wait(); // works as expected, waiting to complete
DoOtherStuff(); // doesn't get hit with await
return;
}
RunRecurringTask(async () => await HandleMessage(), result);
public void RunRecurringTask(Action action, RecurringTaskRunResult result)
{
action();
result.DoStuff();
}
I thought that await tells the thread to come back when the awaited thing is complete, but it looks like for some reason that's not happening: the remaining code is never hit and everything just... stops. What could be causing this?
This is a console application in an Azure WebJob, for what it's worth. When Wait is used, I get the expected results, however with await, the job just completes.
You should never do async void unless you are writing a event handler. A Action with the async modifier is a async void method. You need to make the argument a Func<Task> and then do await action() in your RunRecurringTask
private async Task HandleMessage()
{
await sender.Send();
DoOtherStuff();
return;
}
RunRecurringTask(async () => await HandleMessage(), result);
//You also could do
//RunRecurringTask(() => HandleMessage(), result);
public async Task RunRecurringTask(Func<Task> action, RecurringTaskRunResult result)
{
await action();
result.DoStuff();
}
If you had other methods that where not marked with async you will need to change all of them up the call stack till you get to the entry point from the SDK. The SDK understands how to handle functions with a async Task return type since the 0.4.0-beta version.