多线程学习笔记一
主要:委托的同步调用,异步调用
委托异步调用时的回调函数,几种等待方式。
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 多线程学习
{
/// <summary>
/// 进程 线程 计算机概念
/// 进程:一个程序运行时,占用的全部计算资源的总和
/// 线程:程序执行流的最小单位;任何操作都是由线程完成的;
/// 线程是依托于进程存在的,一个进程可以包含多个线程;
/// 线程也可以有自己的计算资源
/// 多线程:多个执行流同时运行
/// cpu太快,分时间片--上下文切换(加载变量--计算--保存环境)
/// 微观角度,一个核同一时刻只能执行一个线程,宏观来说是多线程并发
/// 多CPU(多核)可以独立工作
/// 4核8线程:核是物理的核,线程是指虚拟核
///
/// Thread是C#语言对线程对象的封装
///
/// 是对方法执行的描述
/// 同步:完成计算之后,再进行下一行
/// 异步:不会等待方法的完成,会直接进入下一行:非阻塞
///
/// C#异步和多线程有什么差别
/// 多线程就是多个thread并发
/// 异步是硬件式的异步
/// 异步多线程--thread pool task
/// </summary>
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Thread.Sleep(11);
}
private void btn_Sync_Click(object sender, EventArgs e)
{
Console.WriteLine("this is a sync method");
Action<string> action = this.DoSomethingLong;
for (int i = 0; i < 5; i++)
{//委托的同步调用:UI界面会卡,应为UI线程在执行计算,无法响应
string name = string.Format($"btn_Sync_Click_{i}");
action.Invoke(name);
}
}
private void btn_Async_Click(object sender, EventArgs e)
{
Console.WriteLine("this is a async method");
{
//委托的同步调用
//Action<string> action = DoSomethingLong;
//action.Invoke("btn_Async_Click_1");
//action("btn_Async_Click_2");
委托的异步调用:异步多线程
//action.BeginInvoke("btn_Async_Click_3",null,null);
委托的同步调用
//action.Invoke("btn_Async_Click_4");
}
{
Action<string> action = this.DoSomethingLong;
for(int i=0;i<5;i++)
{//异步多线程:委托异步调用:不卡界面,主线程完事,计算任务交给子线程
//同步调用:UI界面会卡,应为UI线程在执行计算,无法响应
//同步方法慢,因为只有一个线程工作;异步方法快,因为多个线程并发运算
//并不是线性增长,牺牲资源换取时间,资源可能不够,上下文切换会消耗资源,多线程有管理成本
//线程可以加快速度,但并不是越多越好。
//使用多线程的情况:多个任务可以独立同时运行。
//线程只有操作系统才有,编程时都是进程向操作系统申请的
//同步方法可控性好
//异步方法无序:启动无序:执行时间不确定,结束无序
//一定不要通过等几毫秒的形式来控制线程的启动和结束
//回调/状态等待/信号量
string name = string.Format($"btn_Async_Click_{i}");
action.BeginInvoke(name, null, null);
}
}
Console.WriteLine("async method end");
}
/// <summary>
/// 很耗时的方法
/// </summary>
/// <param name="name"></param>
private void DoSomethingLong(string name)
{
Console.WriteLine("DoSomethingLong Start"+Thread.CurrentThread.ManagedThreadId.ToString("00"));
for(int i=0;i<5;i++)
{
Thread.Sleep(400);
Console.WriteLine(name);
}
Console.WriteLine("DoSomethingLong End");
}
private void btn_AsyncAdvanced_Click(object sender, EventArgs e)
{
Console.WriteLine("btn_AsyncAdvanced_Click Start " + Thread.CurrentThread.ManagedThreadId.ToString("00"));
Action<string> action = this.DoSomethingLong;
IAsyncResult asyncResult = null;
//AsyncCallback callback = new AsyncCallback(ia => Console.WriteLine("到这里计算已经完成" + Thread.CurrentThread.ManagedThreadId.ToString("00")));
//AsyncCallback callback = ia => Console.WriteLine("到这里计算已经完成" + Thread.CurrentThread.ManagedThreadId.ToString("00"));
AsyncCallback callback = ia =>
{
Console.WriteLine(object.ReferenceEquals(asyncResult, ia));
Console.WriteLine(ia.AsyncState);
Console.WriteLine("到这里计算已经完成" + Thread.CurrentThread.ManagedThreadId.ToString("00"));
};
asyncResult=action.BeginInvoke("btn_AsyncAdvanced_Click",callback,"superman");
int i = 0;
//while(!asyncResult.IsCompleted)//1 卡界面,主线程忙于等待
//{//可以等待,边等待边做其他操作,但是会最多延迟200ms
// if(i<10)
// {
// Console.WriteLine($"文件上传完成{(i++)*10}%...");
// }
// else
// {
// Console.WriteLine($"文件上传完成99.9%...");
// }
// Thread.Sleep(200);
//}
Thread.Sleep(200);
Console.WriteLine("Do Something Else...");
Console.WriteLine("Do Something Else...");
Console.WriteLine("Do Something Else...");
asyncResult.AsyncWaitHandle.WaitOne();//等待任务完成,
asyncResult.AsyncWaitHandle.WaitOne(-1);
asyncResult.AsyncWaitHandle.WaitOne(1000);//等待,最多等待1000ms,超过1000ms就不等了
action.EndInvoke(asyncResult);//可以等待,不仅可以等待,还可以获取返回值,
//该等待可以放在回调函数内,也可以放在回调函数外面,但二者只能选其一,否则报错
{
Func<int> func = () =>
{
Thread.Sleep(2000);
return DateTime.Now.Day;
};
Console.WriteLine($"func.Invoke()={func.Invoke()}");
IAsyncResult asyncResult1=func.BeginInvoke(c =>
{
//Console.WriteLine($"func.EndInvoke(c)={func.EndInvoke(c)}");
Console.WriteLine(c.AsyncState);
}, "superman");
Console.WriteLine($"func.EndInvoke(asyncResult1)={func.EndInvoke(asyncResult1)}");
}
Console.WriteLine("文件上传成功!");
Console.WriteLine("全部计算真的完成了" + Thread.CurrentThread.ManagedThreadId.ToString("00"));
//Console.WriteLine("到这里计算已经完成"+ Thread.CurrentThread.ManagedThreadId.ToString("00"));
Console.WriteLine("btn_AsyncAdvanced_Click End " + Thread.CurrentThread.ManagedThreadId.ToString("00"));
}
}
}