C#多线程是C#学习中必不可少的知识,在实际开发中也能有效的提升用户体验,和程序性能。
随着业务的不断发展,程序的数据处理量需求也越来越高,例如,电商项目中的库存同步,和商品信息拉取等,一个门店都是几千个品种,每个品种都有几十甚至上百的的批次,如果是个连锁有一万家门店,那么这种情况库存同步如果用单线程处理的话效率是极其低的,同步几天都同步不完,接下来就该利用多线程来优化了。
协程,英文名是 Coroutine, 又称为微线程,是一种用户态的轻量级线程。协程不像线程和进程那样,需要进行系统内核上的上下文切换,协程的上下文切换是由程序员决定的。
协程的本质是个单线程,它不能同时用上单个 CPU 的多个核,协程需要和进程配合才能运行在多 CPU上。当然我们日常所编写的绝大部分应用都没有这个必要,就比如网络爬虫来说,限制爬虫的速度还有其他的因素,比如网站并发量、网速等问题都会是爬虫速度限制的因素。除非做一些密集型应用,这个时候才可能会用到多进程和协程。
写协程就意味着你要一直写一些非阻塞的代码,使用各种异步版本的库,比如后面的异步爬虫教程中用的 aiohttp 就是一个异步版本的request库等。 不过这些缺点并不能影响到使用协程的优势。
线程,英文名是Thread,线程是进程中的一个实体,作为系统调度和分派的基本单位。Linux下的线程看作轻量级进程。
它是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。
一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器,如果计算密集型线程的数量比可用的处理器多,那么可能会有较大性能损失,性能损失只增加了额外的同步和调度开销,而可用资源不变。
编写多线程需要更全面深入的考虑,在一个多线程程序里面,因时间分配上的细微偏差或者因为共享了不该共享的变量造成的影响很大,线程是缺乏保护的;
进程是访问控制的基本粒度,在一个线程中调用某些OD函数会对整个进程造成影响;
调试多线程程序比单线程程序困难的多。
进程,英文名是:process,当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。 而一个进程又是由多个线程所组成的。
顺序程序的特点:具有封闭性和可再现性;
程序的并发执行和资源共享。多道程序设计出现后,实现了程序的并发执行和资源共享,提高了系统的效率和系统的资源利用率。
操作系统调度切换多个线程要比切换调度进程在速度上快的多。而且进程间内存无法共享,通讯也比较麻烦。
在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
它们之间的关系如下:
进程可以包含多个线程,线程里又可以包含多个协程
在C#中创建线程的方式:
.net Core | .net Framework |
---|---|
不支持 |
支持 |
.net Framework 示例代码:
Func<int, int, int> a = (d, b) => d + b;
a.BeginInvoke(3, 4, CallBack, a);
Console.ReadKey();
static void CallBack(IAsyncResult ar) //系统会自动将该参数填充
{
Func<int, int, int> b = ar.AsyncState as Func<int, int, int>;
int res = b.EndInvoke(ar);
Console.WriteLine("最后得到的结果是:" + res);
}
虽然.net Core 不可以但是这里还是给大家展示
微软官网文档
以下是.net Core6.0实现委托实现AOP的方法
using System.Reflection;
DelegateExtension extension = new DelegateExtension();
Console.WriteLine(extension.Show());
Console.WriteLine("主线程执行...");
Console.Read();
public abstract class BaseAttribute : Attribute
{
public abstract Func<int> Do(Func<int> action);
}
public class BeforAttribute : BaseAttribute
{
public override Func<int> Do(Func<int> action)
{
Console.WriteLine("执行之前基础操作!");
Func<int> acc = new Func<int>(
action.Invoke
);
return acc;
}
}
public class CoreFunc
{
[Befor]
public int Methond()
{
Console.WriteLine("主要执行的方法");
return 1;
}
}
public class DelegateExtension
{
public int Show()
{
CoreFunc ca = new CoreFunc();
//反射对象
Type type = ca.GetType();
MethodInfo methodInfo = type.GetMethod("Methond");
Func<int> action = () => { return Convert.ToInt32(methodInfo.Invoke(ca, null)); };
//判断这个方法上面是否有BeforAttribute 特性,没有就直接执行方法
if (methodInfo.IsDefined(typeof(BeforAttribute), true))
{
foreach (BaseAttribute ba in methodInfo.GetCustomAttributes(typeof(BaseAttribute), true))
{
action = ba.Do(action);
}
}
return action.Invoke();
}
}
.net Core | .net Framework |
---|---|
支持 | 支持 |
以下是代码示例
string name = "子线程传入的参数";
Thread t = new Thread(() => Console.WriteLine(name));
t.Start();
Console.WriteLine("主线程执行");
Console.ReadLine();
.net Core | .net Framework |
---|---|
支持 | 支持 |
void ThreadMethod(object name) { Console.WriteLine("子线程线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString("00")); }
ThreadPool.QueueUserWorkItem(ThreadMethod);
Console.WriteLine("主线程执行");
Console.ReadLine();
.net Core | .net Framework |
---|---|
支持 | 支持 |
//第一种方法
Task task = new Task(() => { Console.WriteLine("第一种方法输出!"); });
task.Start();
//第二种方法
TaskFactory taskF = new TaskFactory();
taskF.StartNew(() => Console.WriteLine("第二种方法输出!"));
//连续型任务(按顺序执行)
Task task = new Task(() => Console.WriteLine("你好"));
task.Start();
Task task2 = task.ContinueWith((a) => Console.WriteLine("hello"));
Console.ReadLine();
参考自”猫不在“博主博客
以上就是线程的一些基础知识,线程涉及的知识还是比较广的,比如线程资源争夺,线程锁,线程权重等知识,后面我会为大家分享并拿实际案例来讲解。