线程 定时器 互斥锁
一、线程的概念。
线程被称为轻量级的进程。GIL:全局解释锁(只有CPython解释器才有)
对于线程来说因为有了GIL所以没有真正的并行。
计算机的执行单位以线程为单位。计算机的最小可执行单位为线程。
进程是资源分配的基本单位。线程是可执行的基本单位,是可被调度的基本单位。
线程不可以自己独立拥有资源。线程的执行,必须依赖于所属进程中的资源。
进程中必须至少应该有一个线程。
线程又分为用户级线程和内核级线程(了解)
线程的组成:
代码段、数据段、线程控制块(TCB)
二、线程和进程的比较
1、cpu切换线程要比cpu切换进程快很多
在python中,如果IO操作比较多的话,使用线程最好。计算密集用多进程。
# 进程和线程在同时调用多个时,时间效率上有很大的差距
om threading import Thread
from multiprocessing import Process
import time
def func():
pass
if __name__ == '__main__':
s = time.time()
for i in range(1000):
p = Process(target=func)
p.start()
print('进程:',time.time() - s)
s1 = time.time()
for i in range(1000):
t = Thread(target=func)
t.start()
print('进程:', time.time() - s1)
2、在同一个进程内,所有线程共享该进程的pid,也就是说所有线程共享所属进程的所有资源和内存地址。
3、在同一个进程内,所有线程共享该进程中的全局变量
4、因为GIL锁的存在,在cpython中,没有真正的线程并行。但是有真正的多进程并行。
5、关于守护进程和守护线程(代码执行结束并不代表程序结束)
守护进程:根据父进程的代码执行结束而结束。
守护线程:根据父线程的执行结束而结束。
# 进程和线程不能同时执行要分别执行才有效果
from threading import Thread
from multiprocessing import Process
import time
def daemon_():
time.sleep(1)
print('守护线程')
def func():
time.sleep(3)
print('普通子线程')
if __name__ == '__main__':
t = Thread(target=func,args=())
t1 = Thread(target=daemon_,args=())
t.start()
t1.daemon = True
t1.start()
# time.sleep(2)
print(666)
# 守护线程是根据主线程执行结束才结束
# 守护线程不是根据主线程的代码执行结束而结束
# 主线程会等待普通线程执行结束,再结束
# 守护线程会等待主线程结束,再结束
# 所以,一般把不重要的事情设置为守护线程
# 守护进程是根据主进程的代码执行完毕,守护进程就结束
def daemon1_():
time.sleep(1)
print('守护进程')
def func1():
time.sleep(2)
print('普通子进程')
if __name__ == '__main__':
p = Process(target=func1,args=())
p1 = Process(target=daemon1_,args=())
p1.daemon = True
p1.start()
p.start()
print(999)
三、线程的使用
1、锁机制
递归锁
RLock() 可以有 无止尽的锁,但是有一把万能钥匙
from threading import RLock
l = RLock()
l.acquire()
l.acquire()
l.acquire()
l.acquire()
print(123) # 不需要去解锁
互斥锁
Lock() 一把锁配一把钥匙
# 用Lock实现互斥锁
from threading import Lock
l = Lock()
l.acquire()
print('123')
l.acquire() # 会造成死锁 一直处于等待状态
l.release()
print('456')
GIL:全局解释锁
锁的是线程,是cpython解释器上的一个锁,意思是在同一时间只允许一个线程访问cpu
2、信号量:
from threading import Semaphore 和进程类似
from threading import Thread,Semaphore,Lock
def func(l,i):
l.acquire() # 5个人可以同时打开这把锁
print('第%s个'% i)
l.release() # 5个人可以同时离开并锁上锁
if __name__ == '__main__':
sem = Semaphore(5) # 一把锁配了5把钥匙
for i in range(5):
t = Thread(target=func,args=(sem,i))
t.start()
3、事件:
from threading import Event 和进程类似
rom threading import Event,Thread
import time,random
def conn_mysql(e,i):
c = 1
while c <= 3:
if e.is_set():
print('\033[42m 连接成功 \033[0m')
break
else:
print('\033[43m 连接失败 \033[0m')
e.wait(0.5)
c += 1
def check_mysql(e):
print('数据库正在连接。。。。')
time.sleep(random.randint(1,2))
e.set()
if __name__ == '__main__':
e = Event()
t_check = Thread(target=check_mysql,args=(e,))
t_check.start()
for i in range(10):
t_conn = Thread(target=conn_mysql, args=(e,i))
t_conn.start()
4、条件
from threading import Condition
条件是让程序员自行去调度线程的一个机制
Condition 涉及4个方法
acquire()
release()
wait() 是指让线程阻塞住
notify(int) 是指给wait发一个信号,让wait变成不阻塞
int是指,你要给wait发的信号是多少
from threading import Thread,Condition
def func(i,con):
con.acquire()
con.wait() # 线程执行到这里会阻塞,等待notify发送信号,来唤醒这批线程。
con.release()
print('第%s个执行'% i)
if __name__ == '__main__':
con = Condition() # 实例化
while 1:
for i in range(10):
t = Thread(target=func, args=(i, con))
t.start()
num = int(input('>>>'))
con.acquire()
con.notify(num) # 发送一个信号给num个正阻塞在wait的线程,让这些线程正常执行。
con.release()
5、定时器
from threading import Timer
Timer(time,func)
time:睡眠的时间,以秒为单位
func:睡眠之后,需要执行的任务
from threading import Timer
def func():
print('123')
if __name__ == '__main__':
t = Timer(3,func) # 意思为3秒以后执行func函数
t.start()