C# 并发编程 - 基本概念

并发: 通俗理解就是可以同时做很多事。终端用户程序利用并发功能, 在输入数据库的同时响应用户输入。服务器应用利用并                    发,在处理第一个请求的同时响应第二个请求。 

多线程: 并发的一种形式, 它采用多个线程来执行程序, 达到并发的效果。

并行处理: 把正在执行的大量的任务分割成小块, 分配给多个同时运行的线程。 对应于现在的多核CPU, 在执行大量任务时,                       并行处理把任务分割成小块并分配给多个线程, 让它们在不同的核上独立运行。
 

Note: 并行处理是多线程的一种, 而多线程是并发的一种

还有一种并发类型: 异步编程

Note: 异步编程的核心理念是异步操作:启动了的操作将会在一段时间后完成。这个操作正在执行时,不会阻塞原来的线程。启动了这个操作的线程,可以继续执行其他任务。当操作完成时, 会通知它的 future, 或者回调函数, 以便让程序知道操作已经结束。

并发编程的另一种形式是响应式编程(reactive programming)。异步编程意味着程序启动一个操作,而该操作将会在一段时间后完成。响应式编程与异步编程非常类似, 不过它是基于异步事件(asynchronous event)的, 而不是异步操作(asynchronous operation)。异步事件可以没有一个实际的开始, 可以在任何时间发生, 并且可以发生多次, 例如用户输入。

响应式编程: 一种声明式的编程, 程序在该模式中对时间做出响应。

 

现代的异步.NET程序使用两个关键字:async 和 await。 async关键字加在方法声明上, 它的主要目的是使方法内的await关键字生效。如果async方法有返回值, 应返回Task;如果没有返回值,应返回Task。 这些task类型相当于future, 用来在异步方法结束时通知主程序。

Note: 不要用void作为async方法的返回类型! async方法可以返回void, 但是这仅限于编写时间处理程序。一个普通的async方法如果没有返回值, 要返回Task, 而不是void。

一个简单的例子:

using System;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace asnyc1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            await DoSomethingAsync(); //此时label1会等DoSomethingAsync完成之后再显示Done, label2先显示26
            label1.Text = "Done!";

        }

        //private void button1_Click(object sender, EventArgs e)
        //{
        //    DoSomethingAsync();
        //    label1.Text = "Done!";      //此时label1先显示Done, 然后label2再显示26  

        //}

        async Task DoSomethingAsync()
        {
            int val = 13;
            await Task.Delay(TimeSpan.FromSeconds(1)); //wait 1 second asynchronously
            val *= 2;

            await Task.Delay(TimeSpan.FromSeconds(1)); //wait 1 second asynchronously

            label2.Text = val.ToString();
        }
    }
}
 

Note: async方法在开始以同步的方式执行。在async方法内部, await 关键字对它的参数执行一个异步等待。它首先检查操作是否完成, 如果完成了, 就继续执行(同步方式)。否则, 它会暂停async方法, 并返回, 留下一个未完成的task。一段时间后, 操作完成, async方法就恢复运行

 

一个async方法是由多个同步执行的程序块组成的, 每个同步程序块之间由await语句分隔

 

在上面的代码中,每个同步程序块会试图在原始的上下文中恢复运行。如果在UI线程中调用DoSomethingAsync,这个方法的每个同步程序块都将在此UI 线程上运行。但是,如果在线程池线程中调用,每个同步程序块将在线程池线程上运行。要避免这种错误行为, 可以在await 中使用ConfigureAwait 方法, 将参数continueOnCapturedContext 设为false。接下来的代码刚开始会在调用的线程里运行,在被await 暂停后,则会在线程池线程里继续运行:

using System;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace asnyc1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //private async void button1_Click(object sender, EventArgs e)
        //{
        //    await DoSomethingAsync(); //此时label1会等DoSomethingAsync完成之后再显示Done, label2先显示26
        //    label1.Text = "Done!";

        //}

        private void button1_Click(object sender, EventArgs e)
        {
            DoSomethingAsync();
            label1.Text = "Done!";      //此时label1先显示Done, 然后label2再显示26  

        }

        async Task DoSomethingAsync()
        {
            int val = 13;
            await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); //wait 1 second asynchronously
            val *= 2; //从这里开始在新线程中运行

            await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); //wait 1 second asynchronously

            label2.Text = val.ToString();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false;   //支持跨线程检查
        }
    }
}
 

参考书籍: C#并发编程经典实例

Note: 最好的做法是, 在核心库代码中一直使用ConfigureAwaiter。在外围的用户界面代码中, 只在需要时才恢复上下文。

你可能感兴趣的:(C#)