参考微软网页:
使用 Async 和 Await 的异步编程 (C#)
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/index
演练:使用 Async 和 Await 访问 Web (C#)
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/walkthrough-accessing-the-web-by-using-async-and-await
await(C# 参考)
https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/await
今天做async await实验时发现一个奇怪的语法现象:
static void test()
{
Console.WriteLine("asyncawaittest");
}
private void btnasyncawait_Click(object sender, EventArgs e)
{
new Thread(test) { IsBackground = true }.Start(); //**注意** IsBackground = true后面没有分号“;”
//new Thread(test) { IsBackground = true, Name = "mythreadname" }.Start(); //也成功
}
以上代码成功,改成如下代码也成功:
static void test()
{
Console.WriteLine("asyncawaittest thread id = "+Thread.CurrentThread.ManagedThreadId+" thread name="+Thread.CurrentThread.Name);
}
private void btnasyncawait_Click(object sender, EventArgs e)
{
Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId);
new Thread(test) { IsBackground = true, Name = "mythreadname" }.Start();//**注意**
}
但在true后面加上一个分号之后出现语法错误。后来通过学习才明白这种用法在叫做“对象初始化器”,比如:
Person person = new Person();
person.Name = "Slark";
person.Age = 100;
person.Address = "Xi'an";
这里我们用了一行创建对象语句,加三行赋值语句。这里光person这个变量就出现了4遍,繁琐。用对象初始化器来代替这些操作:
Person person = new Person { Name = "Slark", Age = 100, Address = "Xi'an" };
c#中除了对象初始化器之外,还有集合初始化器:
List<int> intList = new List<int>();
intList.Add(1);
intList.Add(2);
intList.Add(3);
好,这里我们用4行代码创建了一个3个元素的集合。集合初始化器的出现大大减少了我们对这种操作的代码量。其对应的集合初始化器代码为:
List<int> intList = new List<int> { 1, 2, 3 };
下面来真正进入async和await学习中来,先看一段代码:
private void btnasyncawait_Click(object sender, EventArgs e)
{
Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId);
Say();
}
private async static void Say()
{
Console.WriteLine("Say thread id = " + Thread.CurrentThread.ManagedThreadId);
var t = TestAsync();
Thread.Sleep(1100); //主线程在执行一些任务
Console.WriteLine("Main Thread"); //主线程完成标记
Console.WriteLine(await t); //await 主线程等待取异步返回结果
}
static async Task<string> TestAsync()
{
return await Task.Run(() =>
{
Console.WriteLine("await task thread id = " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000); //异步执行一些任务
return "Hello World"; //异步执行完成标记
});
}
以上代码可以成功运行,点击按钮再次,结果如下:
main thread id = 8
Say thread id = 8
await task thread id = 9
Main Thread
Hello World
main thread id = 8
Say thread id = 8
await task thread id = 9
Main Thread
Hello World
去掉TestAsync()中的async和await即代码如下时:
static Task<string> TestAsync()
{
return Task.Run(() =>
{
Console.WriteLine("await task thread id = " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000); //异步执行一些任务
return "Hello World"; //异步执行完成标记
});
}
代码也能成功运行,点击按钮再次,结果如下:
main thread id = 8
Say thread id = 8
await task thread id = 9
Main Thread
Hello World
main thread id = 8
Say thread id = 8
await task thread id = 10
Main Thread
Hello World
当我将代码修改如下时,发现一个很不明白的现象(主要是将Say()函数中的t之前的await去掉了):
private void btnasyncawait_Click(object sender, EventArgs e)
{
Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId);
Say();
}
private async static void Say()
{
Console.WriteLine("Say thread id = " + Thread.CurrentThread.ManagedThreadId);
var t = TestAsync();
Thread.Sleep(1100); //主线程在执行一些任务
Console.WriteLine("Main Thread"); //主线程完成标记
Console.WriteLine( t); //注意此处t之前没有await
}
static async Task<string> TestAsync()
{
return await Task.Run(() =>
{
Console.WriteLine("await task thread id = " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000); //异步执行一些任务
return "Hello World"; //异步执行完成标记
});
}
打印出来的结果为:
main thread id = 10
Say thread id = 10
await task thread id = 11
Main Thread
System.Threading.Tasks.Task`1[System.String]
再将代码修改如下:
private void btnasyncawait_Click(object sender, EventArgs e)
{
Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId);
Say();
}
private async static void Say()
{
Console.WriteLine("Say thread id = " + Thread.CurrentThread.ManagedThreadId);
var t = TestAsync();
Thread.Sleep(1100); //主线程在执行一些任务
Console.WriteLine("Main Thread"); //主线程完成标记
Console.WriteLine( t);
}
static Task<string> TestAsync()
{
return Task.Run(() =>
{
Console.WriteLine("await task thread id = " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000); //异步执行一些任务
return "Hello World"; //异步执行完成标记
});
}
打印结果如下:
main thread id = 9
Say thread id = 9
await task thread id = 10
Main Thread
System.Threading.Tasks.Task`1[System.String]
还有一段测试代码如下:
private void trfun()
{
var ttr = Task.Run<String>(() =>
{
Thread.Sleep(3000);
return "abc";
});
string rs = ttr.Result;//阻塞3秒
Console.WriteLine("ttr.result=" + rs);
}
主程序中调用trfun()函数,则主程序要等待大约3秒钟之后才打印出结果abc之后才往下执行。换成如下代码:
private void btnasyncawait_Click(object sender, EventArgs e)
{
Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId);
trfun();
Say();
}
private async void trfun()
{
var ttr = Task.Run<String>(() =>
{
Thread.Sleep(3000);
return "abc";
});
string rs = await ttr;//当程序执行到此句时不会再向下反而是快速进入btnasyncawait_Click中的Say()
Console.WriteLine("trfun thread id = " + Thread.CurrentThread.ManagedThreadId);//此句需要等3秒才能执行,且处于主线程ID中
Console.WriteLine("ttr.result=" + rs);
}
打印出来的结果如下:
main thread id = 9
Say thread id = 9
await task thread id = 11
Main Thread
Hello World
trfun thread id = 9
ttr.result=abc
这种异步处理对于btnasyncawait_Click及其主线程来说不会阻塞,阻塞的只是trfun中的await ttr语句。
还有一篇帖子 C#Winform里的async和await异步 https://blog.csdn.net/liuqianggege1/article/details/48135301 讲得也不错
1个按钮,2个textbox,下面这样可以正确异步,窗体也不会死掉,textBox2会先有结果,textBox1再有结果
private async void button1_Click(object sender, EventArgs e)
{
Does();
textBox2.Text = "1";
}
private Task<string> DoWork()
{
return Task.Run(() =>
{
Thread.Sleep(4000);
return "Done with work!";
}
);
}
private async void Does()
{
string text = await DoWork();
textBox1.Text = text;
}
如果把按钮事件改成下面这样,窗体不会死,但不会异步执行
private async void button1_Click(object sender, EventArgs e)
{
textBox2.Text =await DoWork();
textBox2.Text = "1";
}