I want to test async and await in a C# console application, so I write this test code. when I use async/await in a Winforms application, for example: call this doSth in a ButtonClicked event handler function. it will do delay 3000ms in another thread, and output "doSth execute finished" in MainThread. but in this console application, it output "doSth execute finished" in the working thread, why?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp12
{
class Program
{
static void Main(string[] args)
{
doSth();
Console.WriteLine("doSth call finished.");
Thread.Sleep(5000);
Console.WriteLine("Main finished.");
}
private static async void doSth()
{
Console.WriteLine("doSth execute Started...");
await Task.Delay(3000);
Console.WriteLine("doSth execute finished.");
}
}
}
this is the test code in Winforms application
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
doSth();
Console.WriteLine("doSth call finished.");
Thread.Sleep(5000);
Console.WriteLine("Main finished.");
}
private static async void doSth()
{
Console.WriteLine("doSth execute Started...");
await Task.Delay(3000);
Console.WriteLine("doSth execute finished.");
}
}
}
this is the stack trace in console application, the finally output is :
doSth execute Started...
doSth call finished.
doSth execute finished.
Main finished.
请按任意键继续. . .
this is the stack trace in Winforms application, the output is :
doSth execute finished.
doSth execute Started...
doSth call finished.
Main finished.
if I delete Thread.Sleep(5000) and make the main thread don't sleep, and in console application, it will lose the output and the second output of doSth function will not be called. in Winforms application, there is no effect.
CodePudding user response:
First of all, async/await does not mean that there will be other threads executing. If await operator is hit, then the execution of that piece of code stops there (and awaits), while this operation waits, the same thread can pick up some more work (some more tasks to do).
So asynchronous code is rather about reusing the same threads as much as possible and not about spanning execution of code across as many threads as possible.
When deleting Thread.Sleep
you simply leave work undone. You just finish running application while there task in the background still running. But it's terminated with your application.
CodePudding user response:
Ultimately, any time you type async void
, you're probably making a mistake (with a slight caveat around event-handlers on winforms); the fix here is to await things (if your only non-background thread, i.e. the Main
entry-point, exits: then a console application terminates):
static async Task Main(string[] args)
{
await doSthAsync();
// ...
}
private static async Task doSthAsync() {...}
Note that async and concurrency/parallelism are very different things; if your intentions were to achieve concurrency, then maybe:
static async Task Main(string[] args)
{
var pending = Task.Run(doSthAsync);
// ...
await pending; // to allow parallel work to finish
}