As I know, asynchronous functions return immediately. The sample code below confirms me.
static void Main(string[] args)
{
StartTasks2();
Console.ReadKey();
}
private static void StartTasks2()
{
Console.WriteLine($"Task2 Started: {DateTime.Now:s.ffff}");
AddPersonFake();
Console.WriteLine($"Task2 Finished: {DateTime.Now:s.ffff}");
}
private static async void AddPersonFake()
{
Console.WriteLine($"AddPersonFake Started: {DateTime.Now:s.ffff}");
await Task.Delay(2000);
Console.WriteLine($"AddPersonFake Finished: {DateTime.Now:s.ffff}");
}
But this code is not working (I'm waiting for the result as above):
static void Main(string[] args)
{
StartTasks1();
Console.ReadKey();
}
private static void StartTasks1()
{
Console.WriteLine($"Task1 Started: {DateTime.Now:s.ffff}");
AddPerson();
Console.WriteLine($"Task1 Finished: {DateTime.Now:s.ffff}");
}
private static async void AddPerson()
{
Console.WriteLine($"AddPerson Started: {DateTime.Now:s.ffff}");
using ( TempDbContext context = new TempDbContext() )
{
context.Persons.Add(new Person());
await context.SaveChangesAsync();
}
Console.WriteLine($"AddPerson Finished: {DateTime.Now:s.ffff}");
}
How can I return immediately from AddPerson()?
From what I learned here on StackOverflow yestarday, you can do it using:
private static async void AddPerson() {
await Task.Yield();
Console.WriteLine($"AddPerson Started: {DateTime.Now:s.ffff}");
using ( TempDbContext context = new TempDbContext() ) {
context.Persons.Add(new Person());
await context.SaveChangesAsync();
}
Console.WriteLine($"AddPerson Finished: {DateTime.Now:s.ffff}");
}
Task.Yield() will start incompeleted Task and when awaiting it, that is the place where your asynchronous code will start.
In your original code, method AddPerson is running synchronously until it reaches the first await
Related
public class Program
{
public static void Main(string[] args)
{
Start();
Console.ReadLine();
}
private static async Task Start()
{
var m1 = method1();
var m2 = method2();
await Task.WhenAll(m1, m2);
}
private static async Task method1()
{
Console.WriteLine("Method1 - Start");
Thread.Sleep(1000);
Console.WriteLine("Method1 - End");
}
private static async Task method2()
{
Console.WriteLine("Method2 - Start");
Thread.Sleep(1000);
Console.WriteLine("Method2 - End");
}
}
The above code returning below out
Method1 - Start
Method1 - End
Method2 - Start
Method2 - End
I want an output like
Method1 - Start
Method2 - Start
Method1 - End
Method2 - End
how to achieve that basically how to run async methods in parallel
Option A - with Task.Delay
public class Program
{
public static async Task Main()
{
await Start();
Console.ReadLine();
}
private static async Task Start()
{
var m1 = method1();
var m2 = method2();
await Task.WhenAll(m1, m2);
}
private static async Task method1()
{
Console.WriteLine("Method1 - Start");
await Task.Delay(1000);
Console.WriteLine("Method1 - End");
}
private static async Task method2()
{
Console.WriteLine("Method2 - Start");
await Task.Delay(1000);
Console.WriteLine("Method2 - End");
}
}
Option B - with Task.Run
public class Program
{
public static async Task Main()
{
await Start();
Console.ReadLine();
}
private static async Task Start()
{
var m1 = Task.Run(() => method1());
var m2 = Task.Run(() => method2());
await Task.WhenAll(m1, m2);
}
private static void method1()
{
Console.WriteLine("Method1 - Start");
Thread.Sleep(1000);
Console.WriteLine("Method1 - End");
}
private static void method2()
{
Console.WriteLine("Method2 - Start");
Thread.Sleep(1000);
Console.WriteLine("Method2 - End");
}
}
Or you can use Task.Yield().
public class Program
{
public static void Main(string[] args)
{
Start();
Console.ReadLine();
}
private static async Task Start()
{
var m1 = method1();
var m2 = method2();
await Task.WhenAll(m1, m2);
}
private static async Task method1()
{
await Task.Yield();
Console.WriteLine("Method1 - Start");
Thread.Sleep(1000);
Console.WriteLine("Method1 - End");
}
private static async Task method2()
{
await Task.Yield();
Console.WriteLine("Method2 - Start");
Thread.Sleep(1000);
Console.WriteLine("Method2 - End");
}
}
This one is a bit "more parallel" than using Task.Delay() because it immediately yields back an uncomplete task, but with delay the "asynchronicity" only happens when you reach that line of code. If you have long running sync code before the delay, that will delay the execution of subsequent methods (in this case method2).
Edit
a more detailed explanation on When would I use Task.Yield()?
Hello How make method MethodA start new execution only when finished previous execution?
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
MethodB();
MethodC();
}
public static void MethodA ()
{
Console.WriteLine("Start");
Thread.Sleep(200);
Console.WriteLine("Stop");
}
public static void MethodB()
{
Task.Run(() => MethodA());
}
public static void MethodC()
{
Task.Run(() => MethodA());
}
}
In this case I have this result
Hello World
Start
Start
Stop
Stop
But I need something like this
Hello World
Start
Stop
Start
Stop
The simplest way is to create a static locking object and reference that in MethodA:
private static readonly object _methodALockObject = new object();
public static void MethodA()
{
lock(_methodALockObject)
{
Console.WriteLine("Start");
Thread.Sleep(200);
Console.WriteLine("Stop");
}
}
Try to use async and await:
public static void Main()
{
Task.Run(async () =>
{
await MethodB();
await MethodC();
}).GetAwaiter().GetResult();
}
public static void MethodA()
{
Console.WriteLine("Start");
Thread.Sleep(200);
Console.WriteLine("Stop");
}
public async static Task MethodB()
{
await Task.Run(() => MethodA());
}
public async static Task MethodC()
{
await Task.Run(() => MethodA());
}
async and await keywords help to make your asynchronous code to be executed in syncronous order.
I have initiated some async infinite loops in my WinForm application, but each time I am trying to break out of them, the program hangs up. I have read some similar topics where people suggested using CancellationTokens, but I am not able to adapt them to my needs. Here is the relevant part of my code.
static bool processStop = false;
static bool processStopped = false;
//Called once
private async void ProcessData()
{
while (!processStop)
{
await Task.Run
(
() =>
{
//Do stuff and call regular not async methods
}
);
}
processStopped = true;
}
//Button click handler to exit WinForm
btnExit.Click += (senders, args) =>
{
processStop = true;
//Programm hangs up here
while (!processStopped);
FormMain.Close();
}
Edited the code
The variables are static.
The Close method is the default Close() method for Forms.
The problem is that the call to Task.Run continues on the main thread. processStop = true; and while (!processStopped); execute synchronously one after the other. This doesn't let the ProcessData method continue its execution and a deadlock occures.
I see a couple of solutions:
Use ConfigureAwait(false) with Task.Run:
private async void ProcessData()
{
while (!processStop)
{
await Task.Run
(
() =>
{
//Do stuff and call regular not async methods
}
).ConfigureAwait(false);
}
processStopped = true;
}
This will cause the ProcessData to continue on a thread pool and you already use a thread pool by calling Task.Run, so it is not a great solution
Wrap the whole process in Task.Run:
static volatile bool processStop = false;
static volatile bool processStopped = false;
//Called once
private async void ProcessData()
{
await Task.Run(() =>
{
while (!processStop)
{
...
}
processStopped = true;
});
}
This would require changing the form of the method passed to work with the loop in it.
Make ProcessData a synchronous method to process CPU-intensive tasks and call it properly. CancellationToken would be the preferred way to cancel the task:
private void ProcessData(CancellationToken token)
{
while(!token.IsCancellationRequested)
{
// do work
}
}
And call it with this:
Task processingTask;
CancellationTokenSource cts;
void StartProcessing()
{
cts = new CancellationTokenSource();
processingTask = Task.Run(() => ProcessData(cts.Token), cts.Token);
}
btnExit.Click += async (senders, args) =>
{
cts.Cancel();
try
{
await processingTask;
}
finally
{
FormMain.Close();
}
}
If you want to spin a bunch of tasks without blocking you can do this:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//Called once
private async Task ProcessData()
{
int count = 0;
while (true)
{
await Task.Run
(
() =>
{
this.Invoke(new Action(() => {
label2.Text = (count++).ToString();
label1.Text = DateTime.Now.ToString(); }));
Thread.Sleep(100);
}
);
}
Debugger.Break(); //you will never see this hit at all
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
private async void button2_Click(object sender, EventArgs e)
{
await ProcessData();
}
}
}
I have a callback function which needs to takes several seconds to process and should be a async method, but I can't find a way to execute this async callback by await because it must be a Delegate param in the calling method.
Here is some piece of code:
async Task Callback(){//do some callback..}
async Task DoSomething(Func<Task> callback){//I want to execute the callback like: await callback();}
async void Main(){ DoSomething(Callback);}
Sorry for my poor english, any idea to do that? Thanks!
You will have to await first call itself.
change
async void Main(){ DoSomething(Callback);}
to
async void Main(){ await DoSomething(Callback);}
After that It should work, I tested with your sample code. Please verify at your end.
class Program
{
static void Main(string[] args)
{
(new Test()).Main();
Console.ReadKey();
}
}
public class Test
{
async Task Callback()
{
Console.WriteLine("I'm in callback");
}
async Task DoSomething(Func<Task> callback)
{
Console.WriteLine("I'm in DoSomething");
await callback();
}
public async void Main()
{
Console.WriteLine("I'm in Main");
await DoSomething(Callback);
Console.WriteLine("Execution completed");
}
}
Here is output
This might have a very simple answer, already posted here somewhere, but there is also a lot of old misleading information about threads.
My question is this: How do I prevent my Console from terminating before the background work is complete? Since the Task is created far down in the business layers of my program, I do not have access to it when the Console terminates (not like in this simple example). Is there some way of awaiting all Tasks that have been created within the context of my application?
public class Program
{
private static void Main(string[] args)
{
DoBackgroundWork();
System.Console.WriteLine("Doing something else during background work");
// Wait for all created Tasks to complete before terminating
???
}
private static void DoBackgroundWork()
{
var task = Task.Run(() =>
{
System.Console.WriteLine("Starting background work");
Thread.Sleep(10000);
System.Console.WriteLine("Background work finished!");
});
}
}
Return the task so that you can wait on it.
private static void Main(string[] args)
{
var task = DoBackgroundWork();
System.Console.WriteLine("Doing something else during background work");
// Wait for all created Tasks to complete before terminating
task.Wait();
}
private static Task DoBackgroundWork()
{
var task = Task.Run(() =>
{
System.Console.WriteLine("Starting background work");
Thread.Sleep(1000);
System.Console.WriteLine("Background work finished!");
});
return task;
}