C#异步和多线程
打开电脑的任务管理器可以发现,每一个程序都是一个进程。所谓进程就是一个程序运行时,占用的全部计算机资源的总和。
线程就是程序执行流的最小单位。任何操作系统都是线程完成的,线程是依托于进程存在的,一个进程可以包含多个线程,线程也可以有自己的计算资源。
同步:完成计算之后,才会进入下一行。异步:不会等待方法的完成,会直接进入下一行。是非阻塞。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 异步方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnAsync_Click(object sender, EventArgs e)
{
Console.WriteLine($"*************************************btnAsync_Click Start {Thread.CurrentThread.ManagedThreadId} ");
//实例化一个委托
Action<string> action = this.DoSomethingLong;
//同步的多线程
action.Invoke("btnAsync_Click1");
//同步的多线程
action("btnAsync_Click2");
//通过委托的异步调用
action.BeginInvoke("btnAsync_Click3", null, null);
Console.WriteLine($"*************************************btnAsync_Click End {Thread.CurrentThread.ManagedThreadId} ");
}
/// <summary>
/// 一个比较耗时耗资源的私有方法。
/// </summary>
/// <param name="name"></param>
private void DoSomethingLong(string name)
{
Console.WriteLine($"*************************************DoSomethingLong Start{Thread.CurrentThread.ManagedThreadId} ");
Console.WriteLine($"hell world ");
Console.WriteLine($"*************************************DoSomethingLong End{Thread.CurrentThread.ManagedThreadId} ");
}
/// <summary>
/// 同步方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSync_Click(object sender, EventArgs e)
{
Console.WriteLine($"*************************************btnSync_Click Start {Thread.CurrentThread.ManagedThreadId} ");
int j = 3;
int k = 5;
int m = j + k;
for (int i = 0; i < 5; i++)
{
string name = string.Format($"btnSync_Click{i}");
this.DoSomethingLong(name);
}
Console.WriteLine($"*************************************btnSync_Click End {Thread.CurrentThread.ManagedThreadId} ");
}
}
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 异步方法
/// 1 同步方法卡界面: 主线程也叫UI线程,在启动界面时就已经分配好了,忙于计算就不能执行其它的了
/// 异步多线程方法不卡界面,主线程完事了,计算任务交给子线程。
/// 2 异步多线程方法快,因为多个线程并发运算;多个独立任务可以同时运行。
/// 3 异步多线程无序:启动无序,执行时间不确定,结束也无序;
/// 4
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnAsync_Click(object sender, EventArgs e)
{
Console.WriteLine($"*************************************btnAsync_Click Start {Thread.CurrentThread.ManagedThreadId} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
////实例化一个委托
//Action<string> action = this.DoSomethingLong;
////同步的多线程
//action.Invoke("btnAsync_Click1");
////同步的多线程
//action("btnAsync_Click2");
////通过委托的异步调用
//action.BeginInvoke("btnAsync_Click3", null, null);
Action<string> action = this.DoSomethingLong;
for (int i = 0; i < 5; i++)
{
string name = string.Format($"btnAsync_Click{i}");
action.BeginInvoke(name, null, null);
}
Console.WriteLine($"*************************************btnAsync_Click End {Thread.CurrentThread.ManagedThreadId} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
/// <summary>
/// 一个比较耗时耗资源的私有方法。
/// </summary>
/// <param name="name"></param>
private void DoSomethingLong(string name)
{
Console.WriteLine($"*************************************DoSomethingLong Start{Thread.CurrentThread.ManagedThreadId} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
long lResult = 0;
for (int i = 0; i < 1000000; i++)
{
lResult += i;
}
Console.WriteLine($"DoSomethingLong {name}");
Thread.Sleep(2000);
Console.WriteLine($"*************************************DoSomethingLong End{Thread.CurrentThread.ManagedThreadId} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
/// <summary>
/// 同步方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSync_Click(object sender, EventArgs e)
{
Console.WriteLine($"*************************************btnSync_Click Start {Thread.CurrentThread.ManagedThreadId} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
int j = 3;
int k = 5;
int m = j + k;
for (int i = 0; i < 5; i++)
{
string name = string.Format($"btnSync_Click{i}");
this.DoSomethingLong(name);
}
Console.WriteLine($"*************************************btnSync_Click End {Thread.CurrentThread.ManagedThreadId} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
/// <summary>
/// 异步进阶
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnAsyncAdvanced_Click(object sender, EventArgs e)
{
Console.WriteLine($"*************************************btnAsyncAdvanced_Click Start {Thread.CurrentThread.ManagedThreadId} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
//实例化一个委托
Action<string> act = this.DoSomethingLong;
IAsyncResult asyncResult = null;
AsyncCallback callback = ia =>
{
//Console.WriteLine(object.ReferenceEquals(asyncResult, ia)); //比较是否相等
//Console.WriteLine(ia.AsyncState); //返回BeginInvoke的第三个参数
//Console.WriteLine("到这里计算已经完成了。");
};
//将BeginInvoke运行的返回值asyncResult传给callback回调函数去执行
asyncResult = act.BeginInvoke("btnAsyncAdvanced_Click", callback, "hello");
/*
int i = 0;
while (! asyncResult.IsCompleted)
{
if (i<10)
{
Console.WriteLine($"文件上传完成 {i++ *10}%...");
}
else
{
Console.WriteLine($"文件上传完成99.9%...");
}
Thread.Sleep(200);
}
Console.WriteLine($"文件上传完成");
*/
/*
Thread.Sleep(200);
Console.WriteLine($"Do Something Else......");
Console.WriteLine($"Do Something Else......");
Console.WriteLine($"Do Something Else......");
Console.WriteLine($"Do Something Else......");
asyncResult.AsyncWaitHandle.WaitOne(); //以信号量的方式等待任务的完成。
*/
Func<int> fuc = () =>
{
Thread.Sleep(2000);
return DateTime.Now.Day;
};
Console.WriteLine($"fuc.Invoke()={fuc.Invoke()}");
IAsyncResult asyRest = fuc.BeginInvoke(r =>
{
Console.WriteLine(r.AsyncState);
}, "hello world");
Console.WriteLine($"fuc.EndInvoke()={fuc.EndInvoke(asyRest)}"); //EndInvok可以等待还可以获取返回值。
Console.WriteLine($"*************************************btnAsyncAdvanced_Click End {Thread.CurrentThread.ManagedThreadId} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
多线程中临时变量的使用,如下列图片中name的不同用法就是临时变量的用法。
多线程中的等待,此时的等待,主线程是处于顺序,主线程会卡界面。用于顺序的完成。
多线程中顺序完成,主线程不会卡界面。用于顺序的完成
多线程不卡主线程等待完成的常用方式。