一、线程
线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程
车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线
流水线的工作需要电源,电源就相当于cpu
所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。
进程是资源分配的最小单位,线程是CPU调度的最小单位。每一个进程中至少有一个线程。
二、开启线程的两种方式
method 1 :
from threading import Thread
import time
def task(n):
print(f"线程{n}开始")
time.sleep(2)
print(f"线程{n}结束")
if __name__ == '__main__':
t = Thread(target=task,args=(1,))
t.start()
t2 = Thread(target=task, args=(2,))
t2.start()
print("主")
method 2 :
from threading import Thread
import time
class MyThread(Thread):
def __init__(self, name):
super().__init__()
self.name = name
def run(self) -> None:
print(f"进程{self.name}开始")
time.sleep(2)
print(f"进程{self.name}结束")
if __name__ == '__main__':
t = MyThread("1")
t.start()
t1 = MyThread("2")
t1.start()
t.join()
t1.join()
print("主")
三、统一进程下多线程数据共享
from threading import Thread
import time
money = 99
def task(n):
global money
money=n
print('开始')
# time.sleep(n)
print('结束')
if __name__ == '__main__':
t = Thread(target=task, args=(2,))
t.start()
t1 = Thread(target=task, args=(66,))
t1.start()
t.join()
t1.join()
print(money)
print('主')
线程相关的其他方法:
Thread实例对象的方法:
- isAlive(): 返回线程是否活动的。
- getName(): 返回线程名。
- setName(): 设置线程名。
threading模块提供的一些方法:
- threading.currentThread(): 返回当前的线程变量。
- threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
- threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
四、守护线程
无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁
需要强调的是:运行完毕并非终止运行
-
1.对主进程来说,运行完毕指的是主进程代码运行完毕
-
2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕
详细解释:
-
1 主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束。
-
2 主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。
五、GIL全局解释器锁
在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势。
-
python的解释器有很多,cpython,jpython,pypy(python写的解释器)
-
python的库多,库都是基于cpython写起来的,其他解释器没有那么多的库
-
cpython中有一个全局大锁,每条线程要执行,必须获取到这个锁
-
这个锁存在的原因是因为python的垃圾回收机制
-
python的多线程其实就是单线程
-
某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行
-
总结:cpython解释器中有一个全局锁(GIL),线程必须获取到GIL才能执行,我们开的多线程,不管有几个cpu,同一时刻,只有一个线程在执行(python的多线程,不能利用多核优势)
-
如果是io密集型操作:开多线程
-
如果是计算密集型:开多进程
网友评论