线程
1.啥是线程:
是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位
2.理解
对于线程的理解,我是在当初学操作系统的时候理解的。那时候只知道,线程是进程引发出来的。但对于为啥引发现在记不清了。所以现在重新复习一下线程。
之所以提出线程是因为之前学的进程有一定的局限性:
- 进程在一个时间段只能干一件事情。
- 进程之间的信息不共享,它是封闭的
第一个比较好理解,我来讲讲第二个理由。众所周知,进程与进程之间所用的内存是相互独立的,要想相互传数据会比较麻烦。常用到的一般是队列、其次是管道(管道有数据不安全性)、以及数据共享(也会造成数据不安全)。
家想一下如果把上课当成是一个进程的话,那么我们要做的是耳朵听老师讲课,手上还要记笔记,脑子还要思考问题。进程只能同一时间执行一件事,所以这堂课要么我们一直听,要么一直写(不听就一直写是瞎写吧)、要么一直思考问题(不听不看,那想的是个啥)。如果现在引入线程的话,就可以吧上课听讲这个进程分为三个线程,并且线程之间是数据共享的(安全的),这样的话可以完整的完成听课这个过程。
3.线程和进程的区别
- 地址空间和资源:进程间相互独立,同一进程的各线程间共享。
- 通信:进程间通信IPC,线程间共享一个进程内的多线程的数据。
- 调度和切换:线程几乎不拥有系统资源,所以它很小。调度和切换时耗费力气小
进程是资源分配的最小单位,线程是CPU调度的最小单位.
4.线程的数据共享
这张图说明了进程中的与进程之间的数据是隔离的,而线程之间他们共享进程的代码、数据、文件。
5.全局解锁器
现在提出一个假象:假如有两个线程(A,B)对进程的(橘黄)n进行数据操作。
当一个线程取到进程n=2时,然后回来进行n+1操作。如果这时候,线程B取出n,然后执行n+2操作,然后又放到进程n里。这时候线程A才把结果送到进程中,最后导致一个数被B抢先操作后,结果不正确。
这是就需要用到以前的概念-锁。全局解释器就是这样的一个锁,它的作用是同一时刻只能有一个线程访问cpu。这样做就会牺牲了多线程的优势,但是为了数据安全也不得不这样,这是解释型语言的弊病。为什么大家说python的运行效率不高,这就是其中的一个原因。为了提升效率cpython做出了一点改善,就是给每个线程一定的时间片,进程轮转调度。
多线程只是对cpu的访问,但对io操作没有进行限制
- 高CPU:
计算类 — 高CPU利用率 - 高IO:
爬取网页 200个网页 、qq聊天 、send recv 、 处理日志文件 、 读文件
处理web请求 、读数据库 写数据库
6.线程创建的两种方法
- 面向对象创建
class MyThread(Thread):
def run(self): # 这里名字必须是run
time.sleep(1)
print('这是面向对象的多线程')
if __name__ == '__main__':
for i in range(10):
t = MyThread()
t.start()
- 面向过程的创建
# 面向过程的创建
def func(i):
print('这是面向对象的创建 %s'%i)
if __name__ == '__main__':
for i in range(10):
t = Thread(target=func,args=(i,))
t.start()
7.进程、线程从属关系
def func(n):
time.sleep(1)
print('第%s个线程它的进程id是%s'%(n,os.getpid())) # 这里是一个子线程 ,输出一个进程id
print('主线程,它的进程ID是%s'%os.getpid()) # 这里的print是一个主线程,输出一个进程id
for i in range(10):
t = Thread(target=func,args=(i,))
t.start() # 如果两个id一样 说明启动了多线程 是由一个id相同的进程 启动的
输出结果为:
解释:
说明 主线程和其他的10个线程都是由同一个进程创建出来的。
进程是最小的内存分配单位,线程是操作系统调度的最小单位
线程直接被CPU执行,进程内至少含有一个线程,也可以开启多个线程
知识点:
- 多个线程内部有自己的数据栈,数据不共享,全局变量在多个线程之间是共享的
- 因为有GIL锁(即全局解释器锁)的关系,在Cpython解释器下的python程序 在同一时刻 多个线程中只能有一个线程被CPU执行