1.异步与多线程
异步是当调用者发出一个调用请求之后,调用者不用等待其结果的返回,可以继续进行其他操作,操作结果在请求完成之后返回,通过回调或者其他机制通知调用者。
实现异步可以采用多线程技术,或者交给另外的进程来处理。
异步是一种行为模式,可以用于很多地方。多线程可以用来实现异步行为模式。
和异步相对应的概念应该是同步,同步需要等待执行成功之后才能返回。
异步与多线程,从辩证关系上看,异步和多线程并不是一个同等关系,异步是目的,多线程只是实现异步的一种手段。异步还可以用消息,或者是委托到其他进程来实现。
多个线程之间可以是同步的,也可以是异步的。
I/O操作多用异步的方式,耗时处理的操作多用多线程。
2.线程安全
在WinForm开发中,常见的一个错误就是“线程中操作无效:从不是创建控件XXX的线程访问它。”
这个错误在WinForm开发中是很常见的一种错误。
下面的这段代码就会发生这样的错误。
- private void button4_Click(object sender, EventArgs e)
- {
- var task = new Task(() =>
- {
- this.lblResult.Text = DateTime.Now.ToLongTimeString();
- });
- task.Start();
- }
通常发生在使用多线程的时候,在线程中想要更新界面上的一些控件的信息。因为这些控件是在主线程中创建的,所以在非主线程的其他线程中,对这些控件进行更新操作,会报出这个错误提示。
通过下面的方式来修正这个错误。
- private void button4_Click(object sender, EventArgs e)
- {
- var task = new Task(() =>
- {
- this.lblResult.Invoke(new Action (() => {
- this.lblResult.Text = DateTime.Now.ToLongTimeString();
- }));
- });
- task.Start();
- }
不是在其非主线程中直接更新空间,而是定义一个委托,在非主线程中执行这个委托,在委托中更新控件。来实现在非主线程中更新控件的属性。
3.C#中的async和await实现异步
有时候为了不阻塞主线程,也就是通常说的不要阻塞UI,或者UI界面不要“死了”,我们需要使用多线程的技术,把一些计算或者是处理任务交给新的线程,待有结果之后再显示给主线程。
3.1.在async和await之前
在async和await之前,我们使用异步编程,begininvoke,然后再callback中处理显示结果。
- private void button2_Click(object sender, EventArgs e)
- {
- this.lblResult.Text = "starting to ...";
- var compute = new Func<int, string>(i =>
- {
- long result = 1;
- for (int n = 0; n <= i; n++)
- {
- result += 1;
- }
- return result.ToString();
- });
- compute.BeginInvoke(int.MaxValue / 2, new AsyncCallback(ar =>
- {
- #region
- //异步是通过多线程来实现的,lblResult是在主线程中创建的控件,异步是在另外一个线程执行
- //所以不能修改主线程中创建的控件
- //this.lblResult.Text = compute.EndInvoke(ar);
- #endregion
- this.lblResult.Invoke(new MethodInvoker(() =>
- this.lblResult.Text = compute.EndInvoke(ar)));
- }
- ), new object());
- }
3.2.有了async和await之后
async和await是在.NET4.5中引入的异步编程关键字,给我们编写异步代码带来了极大的便利,极大地减少了代码的编写,使我们更加集中于具体业务的实现。
async和await也是一种语法糖。
相当于是同步编程的方式实现异步编程的效果。
- public long DoSomething(int n)
- {
- long result = 1;
- for (int i = 0; i <= n; i++)
- {
- result += 1;
- }
- return result;
- }
- private async void button3_Click(object sender, EventArgs e)
- {
- this.lblResult.Text = "staring to ...";
- var value = await DoSomethingAsync(int.MaxValue / 2);
- this.lblResult.Text = value.ToString();
- }
- private Task<long> DoSomethingAsync(int n)
- {
- return Task.Run<long>(() => DoSomething(n));
- }
参考文献
1.
2.
3.
3.
4.
5.