c#多线程
线程池、Task任务
https://blog.csdn.net/liyou123456789/article/details/120595489
https://www.cnblogs.com/jack-jiang0/p/17618154.html
https://www.toutiao.com/article/7137485547618288169
https://www.toutiao.com/article/7255526505097347599
https://www.php.cn/faq/707792.html
Task任务:
https://www.cnblogs.com/zhaoshujie/p/11082753.html
异步编程模型变迁:
https://blog.csdn.net/github_33372103/article/details/50298885
https://blog.csdn.net/u014677109/article/details/117407617
斐波那契数列
https://blog.csdn.net/a_dafei/article/details/132811671
1。进程?
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,【是系统进行资源分配的基本单位】,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,【进程是线程的容器】。程序是指令、数据及其组织形式的描述,进程是程序的实体。
概括:
进程是程序运行的环境。进程是线程的容器。一个进程可以包含多个线程。
进程是系统进行资源分配的基本单位,而线程是系统进行资源分配的最小单位(线程不能再分)。
https://baike.baidu.com/item/进程/382503
2。线程? 阻塞,卡死, 等待
线程(英语:Thread)是操作系统能够进行【运算调度的最小单位】。它被包含在进程之中,是进程中的实际运作单位。【一条线程指的是进程中一个单一顺序的控制流】,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
概括:线程是操作系统资源调度的最小单位。线程不能独立运行,必须包含在进程中。进程中可以包含多个线程。多线程执行时是并行(异步),无序的。
串行===>顺序(排队)===>阻塞(同步) 单线程
并行===>无序===>非阻塞(异步) 多线程
线程之间要通讯。会有两种方案:同步和异步(推荐)。
单个线程中能不能异步?可以,现在没有技术方案落地。
【多线程肯定是异步。异步不一定是多线程。】
多线程中有N个线程,但主线程只有一个,其他的线程都称为子线程(分线程)。对于单线程程序来说,程序中只有一个线程,这个线程就是主线程。
https://baike.baidu.com/item/线程/103101
Basic Class Library基出类库
A。Thread多线程对象:
实例化:Thread t1 = new Thread(两种委托),没有参数委托;带传递参数委托
多线程管理(被开发者诟病):启动:t1.Start(向线程传递的数据),中止:t1.Abort(),挂起:t1.Suspend(),重启:t1.Resume()
多线程的状态:UnStarted未启动, Running运行中, Suspended已挂起, Aborted已中止, Stoped已停止, ....
多线程等待:t1.Join(毫秒数), Thread.Sleep(毫秒数)
线程状态参考:https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.threadstate?view=netframework-4.8
B。Thread重要属性:
IsAlive 线程状态是否是存活。true存活
IsBackground 是否是后台线程。true后台
ThreadState 线程状态,比IsAlive范围大。
CurrentThread 当前执行的线程。
Name 线程名称
Priority 线程优先级
C。Thread重要方法:
new Thread(两种委托) 构造函数 ThreadStart和ParameterizedThreadStart
t.Start()启动
t.Abord()中止
t.Suspend()挂起
t.Resume()重新开始
t.Join(毫秒数)线程终止前,阻止调用线程
Thread.Sleep(毫秒数)线程休眠,延迟
Thread线程类缺点是不好用(不好控制),如果创建多个线程时,更不好管理。ThreadPool比Thread好一些,但也好不到那去。
线程锁:相对复杂
下载技术:HttpWebRequest(旧) WebRequest(旧), HttpClient(新),WebClient(新)。
3。多线程概念?优点及缺点?
多线程是指程序中包含多个执行流(线程),即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
概括:多线程让程序同时运行多个线程,多个线程并行执行(执行时无顺序)
优点:
可以提高CPU的利用率。大大提高了程序的运行效率,用户体现好,粘性高。
重要:不阻塞,不会卡死
缺点:
a.线程也是程序,所以线程运行需要占用计算机资源,线程越多占用资源也越多。(占内存多)
b.多线程需要协调和管理,所以需要CPU跟踪线程,消耗CPU资源。(占cpu多)
c.线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题。(多线程存在资源共享问题 锁)
d.线程太多会导致控制太复杂,最终可能造成很多Bug。(管理麻烦,容易产生bug)
死锁:某个资源不能空闲。
4。线程池?
.NET Framework2.0时代,出现了一个线程池ThreadPool,是一种池化思想,如果需要使用线程,就可以直接到线程池中去获取直接使用,如果使用完毕,在自动的回放到线程池去;
概括:.net 2.0出现线程池,线程池中可以存在多个线程,让线程池来自动管理(垃圾回收器GC和公共语言运行时CLR)。
好处:解决了部分Thread管理不便的问题,移除了无用的Thread API。提高线程运行性能。
重要API:QueueUserWorkItem(Callback,data)
5。Task任务?
Task在.net 4.0时出现,是在线程池基础上封装而来的,提供了对线程的延续,取消,等待,超时等方面功能。
6。取消任务?
CancellationTokenSource类,CancellationToken结构
CancellationTokenSource cts = new CancellationTokenSource();
cts.Cancel()、cts.IsCancellationRequested属性、cts.Token属性
7。延迟,等待?
Task.Delay(100).Wait(); // 延迟并等待,注意延迟执行也是异步的。
t.Wait() //等待,会阻塞主线程
Task.WaitAny()等待任务数组中任意一个任务完成。result任务数组中第一个完成的任务索引。
Task.WaitAll()等待所有的任务完成,没有返回值
Task.WhenAny()当任务数组中任意一个任务完成的时候,去做其他事情 。返回值Task<T>
Task.WhenAll()当任务数组中所有任务都完成的时候,才去做其他事情 。返回值Task
8。拿分线程结果?分线程向主线程传值?
t.Result属性 配合 Task<T>
线程池、Task任务、async异步方法
https://blog.csdn.net/liyou123456789/article/details/120595489
https://www.cnblogs.com/jack-jiang0/p/17618154.html
https://www.toutiao.com/article/7137485547618288169
https://www.toutiao.com/article/7255526505097347599
https://www.php.cn/faq/707792.html
Task任务:
https://www.cnblogs.com/zhaoshujie/p/11082753.html
https://www.cnblogs.com/sexintercourse/p/17761547.html
https://blog.csdn.net/laizhixue/article/details/137157978
https://www.cnblogs.com/yinjun98/p/12307014.html
async和await:
https://www.jb51.net/program/320717dmz.htm
https://learn.microsoft.com/zh-cn/dotnet/csharp/asynchronous-programming/task-asynchronous-programming-model
https://devblogs.microsoft.com/dotnet-ch/async-await在-c语言中是如何工作的/
异步编程模型变迁:
https://blog.csdn.net/github_33372103/article/details/50298885
https://blog.csdn.net/u014677109/article/details/117407617
1。Task任务重点掌握?
概念:Task是微软在.Net 4.0时代推出来的,也是微软极力推荐的一种多线程的处理方式,Task看起来像一个Thread,实际上,它是在ThreadPool的基础上进行的封装,Task的控制和扩展性很强,在线程的延续、阻塞、取消、超时等方面远胜于Thread和ThreadPool。
a. 如何实例化(多种实例化方案)
b. 如何启动任务
c. 如何向任务中传递数据(委托的使用)
d. 任务如何管理(取消 cts.Token.IsCancellationRequested/cts.Canecl())
e. 任务等待
f. 任务返回值(Task<T>泛型)
g 分线程任务中如何捕获异常(处理分线程任务中的非法情况)
重点API及类总结:
实例化及启动:new Task().Start()/Task.Run()/Task.Factory.StartNew()
线程任务取消:CancellationTokenSource类
线程任务等待:task.Wait()/Task .WaitAny()/Task .WaitAll()/Task .WhenAny()/Task .WhenAll()/factory .ContinueWhenAny()/factory.ContinueWhenAll()
线程任务返回值:Task<T>泛型的应用
2。asnyc和await是什么?
异步编程是一种编程范式(是一种异步解决方案,但它不一定多线程)。C#中的异步编程可以通过Thread,TheadPool,Task,async/await等来实现。
多线程肯定是异步的,即多线程是异步的一种实现方案。而异步不一定是多线程,因为异步也有可能出现在单线程的程序中。
async关键字是一个方法修饰符,用它声明的方法,称为异步方法。
await关键字用来等待一个Task或async方法完成,await关键字必须配合async关键字使用,不能单独应用await关键字。
await只能在async修饰的方法(即异步方法)内使用。
await不会阻塞主线程。并且能保证多个异步代码顺序。用户体验好。
3。await能等待什么?
切记:await关键字不能等待同步代码,只能等待Task或异步方法,且异步方法必须有返回值。
4。asnync和await实现异步方法有什么好处?
a. 即可以保证不阻塞,也可以保证异步执行的顺序。
b. 以同步代码的方式编写异步代码,让语法更加优美。
TaskStatus任务状态

Task构造函数重要重载

线程优先级

线程状态

1.Thread

using System;
using System.Windows.Forms;
namespace _1.Thread
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// 耗时, 主线程主要职责负责界面渲染,运行。耗时的任务(计算工作)应该交给子线程(分线程)处理
while (true)
{
Console.WriteLine("aaa");
}
}
private void button2_Click(object sender, EventArgs e)
{
// 1。创建线程(分线程)
// 两个委托:
//ThreadStart 不带参数 public delegate void ThreadStart();
//ParameterizedThreadStart 带参数 public delegate void ParameterizedThreadStart(object obj);
System.Threading.Thread t1 = new System.Threading.Thread(() =>
{
while (true)
{
System.Threading.Thread.Sleep(3000); // 休眠3秒
Console.WriteLine("aaaa");
}
});
System.Threading.Thread t2 = new System.Threading.Thread((obj) =>
{
while (true)
{
System.Threading.Thread.Sleep(3000); // 休眠3秒
Console.WriteLine("bbbb" + obj.ToString());
}
});
System.Threading.Thread t3 = new System.Threading.Thread(DoWork1);
System.Threading.Thread t4 = new System.Threading.Thread(DoWork2);
// 2。启动线程
t1.Start();
t3.Start();
// 向线程中传递参数。
t2.Start(100);
t4.Start(200);
}
private void DoWork1()
{
while (true)
{
System.Threading.Thread.Sleep(3000); // 休眠3秒
Console.WriteLine("cccc");
}
}
private void DoWork2(object obj)
{
while (true)
{
System.Threading.Thread.Sleep(3000); // 休眠3秒
Console.WriteLine("dddd" + obj.ToString());
}
}
private void button3_Click(object sender, EventArgs e)
{
// 会造成主线程阻塞
System.Threading.Thread.Sleep(3000);
MessageBox.Show("hello world");
}
}
}
2.TheadPoolDemo

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 _2.TheadPoolDemo
{
public partial class Form1 : Form
{
// 自己定义一些管理某个线程的标识。
bool pause = false; // 暂停标识
bool stop = false; // 停止标识
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// WaitCallback public delegate void WaitCallback(object state);
// 把一个“任务”放到线程池中执行。开发者不用在自行管理了。
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
}
private void DoWork(object state)
{
// while循环退出后,DoWork方法()所在的线程会自动销毁。销毁会持续一段时间。
while (progressBar1.Value < 100 && !pause && !stop)
{
Thread.Sleep(500);
try
{
Invoke(new Action(() =>
{
progressBar1.Value += progressBar1.Step;
}));
}
catch
{
}
}
}
private void button2_Click(object sender, EventArgs e)
{
// 暂停标识
pause = true;
}
private void button3_Click(object sender, EventArgs e)
{
// 暂停标识
pause = false;
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
}
private void button4_Click(object sender, EventArgs e)
{
stop = true; // 停止标识
}
}
}
3.TaskDemo

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace _3.TaskDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// A。Task的定义方式推荐:1。Task.Run() 2。new Task() 3。TaskFactory
private void button1_Click(object sender, EventArgs e)
{
// Run()创建并运行一个线程
Task t = Task.Run(() =>
{
while (true)
{
Console.WriteLine("AAAA");
}
});
// 2。new Task(),创建一个线程,但是没有启动,需要调用Start()启动
Task t2 = new Task(() =>
{
while (true)
{
Console.WriteLine("BBBB");
}
});
t2.Start();
// 3。TaskFactory 线程工厂创建线程
TaskFactory tf = new TaskFactory();
tf.StartNew(() =>
{
while (true)
{
Console.WriteLine("CCCC");
}
});
}
private void button2_Click(object sender, EventArgs e)
{
//Task.Run()没有看到可以向线程内部传递参数的重载,向线程中传递能数,通过net Task()。
Task t = new Task((obj) =>
{
while (true)
{
Console.WriteLine(obj);
}
}, 100);
t.Start();
}
int i = 0;
// 创建一个取消标识对象,它可以用来管理线程的取消。Token属性用来产生一个取消标识。Cancel()方法,取消任务。
CancellationTokenSource cts = null;
// 要取消任务,必须使用CancellationToken
// 谁会产生一个Token取消标识呢?CancellationTokenSource对象
private void button3_Click(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
Task.Run(() =>
{
// cts.IsCancellationRequested = false没有取消,true取消。cts.Token.IsCancellationRequested也行。
while (!cts.Token.IsCancellationRequested)
{
Console.WriteLine("AAAA" + i);
i++;
}
}, cts.Token);
//cts = new CancellationTokenSource();
//Task t = new Task(() => { }, cts.Token);
}
private void button4_Click(object sender, EventArgs e)
{
// IsCancellationRequested是只读属性,不能赋值,只能靠Cancel()方法来修改。
//cts.IsCancellationRequested = true;
//cts.Token.IsCancellationRequested = true;
cts.Cancel(); // 取消任务,这个方法会造成cts.IsCancellationRequested的变化成true。
}
private async void button5_Click(object sender, EventArgs e)
{
// 把Task.Run()创建的线程保存到变量t上,为了拿t中返回的结果。
Task<string> t = Task.Run(() =>
{
Console.WriteLine("线程中的其他业务逻辑!");
Thread.Sleep(10000);
return "hello world";
});
//var result = t.Result; // 会阻塞,能保证代码顺序。
var result2 = await t; // await等待,等待的谁? t任务,等待t正常完成。等待是t完成后的结果。
// await 好处:1.线程不会阻塞,2.保证代码异步执行的代码顺序。
// await 要求:只能配合async关键字一起使用,不能单独使用。
Console.WriteLine(result2);
Console.WriteLine("aaaa");
/*Method1();
Method2();
Method3(); // (可等待),异步方法,且有返回值
Method4(); // (可等待),异步方法,且有返回值
Method5(); // (可等待),异步方法,且有返回值*/
}
HttpClient httpClient = new HttpClient();
// 普通方法
public void Method1() { }
// 异步方法:看方法返回值类型,返回值类型前有async关键字,就是异步方法。
// 异步方法,async一般配合void,task,task<T>使用
// void 给控件绑定事件时,才配合void使用, 有一定局限性。
// task, task<T>
public async void Method2()
{
}
public async Task Method3() { }
public async Task<string> Method4()
{
return "hello world";
}
// 多线程肯定是异步的,异步不是一定是多线程。
public Task Method5()
{
return new Task(() =>
{
});
}
private void button6_Click(object sender, EventArgs e)
{
Task t1 = Task.Run(() =>
{
Console.WriteLine("线程1");
});
Task t2 = Task.Run(() =>
{
Thread.Sleep(3000);
Console.WriteLine("线程2");
});
// 当t1,t2任务完成任意一个时,继续执行线程3
//Task.WhenAny(t1, t2).ContinueWith((t) =>
//{
// Console.WriteLine("线程3");
//});
// 当t1,t2任务全部完成时,继续执行线程3
Task.WhenAll(t1, t2).ContinueWith((t) =>
{
Console.WriteLine("线程3");
});
}
private async void button7_Click(object sender, EventArgs e)
{
Task t = Task.Run(async () =>
{
Console.WriteLine("线程1");
// Thread.Sleep(10000); // 休眠,延迟10秒。
await Task.Delay(10000); // 不会阻塞线程。
});
//t.Wait(); // 等待t任务完成,好处:保证顺序。缺点:线程阻塞。
await t;
Console.WriteLine("aaaa");
}
}
}
ThreadDemo

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Http.Headers;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ThreadDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// 使用递归实现斐波那契数列
// 斐波那契数列是从 0 和 1 开始,后面每个数都是前两个数之和的数列。
// 前几项数字:0、1、1、2、3、5、8、13、21、34……。
// 计算公式:第 n 项等于前两项相加,即F(n)=F(n−1)+F(n−2)
// 递归:方法内部调用自己。
// 方法嵌套:就是方法的调用栈。方法执行的顺序流。
public int Fib(int n)
{
if (n == 1 || n == 2)
return 1;
else
return Fib(n - 1) + Fib(n - 2);
}
private void button1_Click(object sender, EventArgs e)
{
//int n = Fib(50);
//MessageBox.Show(n.ToString());
// 1。创建线程
Thread t = new Thread((obj) =>
{
// 分线程中比较耗时的代码
// 分线程和主线程是两个线程。
// 分线程中如何访问主线程中的资源(变量,控件等
// 变量直接通过参数传递给分线程即可。但控件Label1是主线程中的资源(控件)
// 错误:System.InvalidOperationException:“线程间操作无效: 从不是创建控件“label1”的线程访问它。”
// 问题:跨线程访问控件,即:在分线程中访问主线程中的控件?默认不允许的。怎么办?借助Invoke()方法。
int n = (int)obj;
int result = Fib(n);
Invoke(new Action(() =>
{
label1.Text = result.ToString();
}));
});
// 重要的线程属性:
t.IsBackground = true; // 掌握。是否是后台线程。是true,否false。默认false,说明默认是前台线程。前台线程会等待所有线程结束,程序才结束 。如果是后台线程,只要主线程结束,程序就结束,所有分线程会自动销毁。
t.Priority = ThreadPriority.Highest; // 掌握。 线程优先级 线程优先级越高,在分配资源时,越先被分配。
t.Name = "分线程1"; // 线程名称,不建议重复,建议唯一。当没有线程名称时,线程会通过ManagedThreadId线程Id来管理线程。
//t.ManagedThreadId = 2; // 掌握。只读
//t.ThreadState = ThreadState.WaitSleepJoin; // 线程状态,只读
label5.Text = t.ThreadState.ToString(); // 掌握。
label6.Text = t.IsAlive.ToString(); // 了解
// 2。启动线程
t.Start(100);
label5.Text = t.ThreadState.ToString();
label6.Text = t.IsAlive.ToString();
label2.Text = t.Name;
//label3.Text = Thread.CurrentThread.Name;
label3.Text = "主线程的Id:" + Thread.CurrentThread.ManagedThreadId.ToString();
label4.Text = "分线程的Id:" + t.ManagedThreadId.ToString();
// 问:哪段代码是在分线程中执行的?ParameterizedThreadStart委托匹配的方法在分线程中执行,创建线程或启动线程的代码还是在主线程中运行。
//通过测试发现:关闭窗体Form1后,分线程并没有执行完成,也没结束
}
// 嵌套方法定义,C#默认不允许,其他语言如:javascript可以的。
public void Method1() {
}
}
}

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 ThreadDemo
{
public partial class Form2 : Form
{
Thread t = null;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (t == null)
{
t = new Thread(new ThreadStart(DoWork));
t.IsBackground = true;
t.Start();
}
}
private void DoWork()
{
while (progressBar1.Value < 100)
{
Thread.Sleep(500);
Invoke(new Action(() =>
{
// 错误: System.InvalidOperationException:“在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。”
// 解决:主线程关闭后,分线程没有自动销毁造成的。
progressBar1.Value += progressBar1.Step;
}));
}
}
private void button2_Click(object sender, EventArgs e)
{
if (t != null)
{
t.Suspend();// 挂起,废弃,不建议使用。
//t.Join(3000); // 线程中止,线程中止,等待3秒
}
}
private void button3_Click(object sender, EventArgs e)
{
if (t != null)
{
t.Resume(); // 继续,恢复线程,废弃,不建议使用。
}
}
private void button4_Click(object sender, EventArgs e)
{
if (t != null)
{
// 你在停止线程时,线程需要持续一段时间,等待CLR 处理线程的终止。
t.Abort(); // 停止,中断,废弃,不建议使用。
t = null;
progressBar1.Value = 0;
}
}
}
}
更多推荐
所有评论(0)