二、Threading模块
Threading模块
一、Thread类
- 语法:
from threading import Thread
def func():
pass
'''
开启线程不需要再main下执行代码,直接书写即可
但是出于良好的编码习惯,我们还是将启动命令下载main下
'''
if __name__ == '__main__':
p = Thread(group=None,target=None, name=None, args=(), kwargs=None, *, daemon=None)
'''
参数介绍:
1.target = 函数名
如果传递了函数的引用,可以认为这个子线程就执行函数内的代码
2.name =
给线程设定一个名字,可以不设定,数据类型为字符串
3.args = (实参1,...)
给target指定的函数传递的实参,以元组的方式传递
4.kwargs = {'参数名1':'参数值1','参数名2':'参数值2',...}
给target指定的函数传递命名参数,以字典的数据类型
5.group参数未使用,值始终为None
'''
1、start()
启动子进程实例,即创建子线程
- 语法:
from threading import Thread
def zhangsan(name):
print(name)
if __name__ == '__main__':
#创建一个线程对象
p = Thread(target=zhangsan, args=('zhangsan',))
# 创建子线程,并在子线程中执行 zhangsan函数中的代码
# 因为创建线程的开销非常小,几乎是代码一执行线程就创建了,所以子线程中的代码可能会比主线程执行的还要快
p.start()
2、is_alive()
判断指定子线程是否活动,返回bool数据类型
如果存活,返回True
如果死亡,返回False
- 语法:
from threading import Thread
if __name__ == '__main__':
p = Thread(group=None,target=None, name=None, args=(), kwargs=None, *, daemon=None)
# 判断子线程是否存活
print(p.is_alive())
注意:
Thread中的isAlive()方法已经被弃用,被is_alive()方法代替,作用一致
3、name属性/getName()
返回指定线程的别名,默认为Thread-N,N为从1开始递增的整数
如果在实例化进程对象时,Thread类加入name参数,那么此处输出的name值,即为name参数的值
- 语法:
from multiprocessing import Process
p = Thread(target[,name[,args[,kwargs]]])
p.start()
print(p.name) #Thread-1
print(p.getName()) #Thread-1
# 添加name参数
p2 = Thread(name = 'zhangsan')
print(p2.name) #zhangsan
4、join()
join是让主线程等待子线程代码运行结束之后,再继续执行代码,并不会影响子线程代码的运行
join 线程和进程都有join方法,且作用基本一致
- 语法:
from threading import Thread
p = Thread(target[,name[,args[,kwargs]]])
p.join([timeout])
'''
参数介绍:
timeout:指定等待时间,单位秒;超过该时间则阻塞主进程
'''
5、setName()
设置指定线程的name属性,即Thread类中的name参数
- 语法:
from threading import Thread
p = Thread(target[,name[,args[,kwargs]]])
p.setName('zhangsan')
6、daemon属性/setDaemon()
daemon/setDaemon:默认值为False,如果设为True,代表该子线程为后台运行的守护线程,当父线程终止时,该子线程也随之终止,并且设定为True后,该子线程不能创建自己的新线程,必须在该子线程创建之前设置
- 语法:
from threading import Thread
p = Thread(target[,name[,args[,kwargs]]])
p.daemon = True
# 或者 p.setDaemon(True)
# PS:设置守护线程必须在该线程start()代码前,即线程还未创建前设置
p.start()
二、threading模块方法
1、currentThread()
/current_thread()
获取当前线程的Thread类,该类可以调用所有线程方法,实现线程内获取本线程信息
直接输出该类,可以查看到线程名,线程id
- 语法:
import threading
print(threading.currentThread())
#<Thread(Thread-1, started 10224)>
print(type(threading.currentThread()))
#<class 'threading.Thread'>
2、enumerate()
返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
import threading
print(threading.current_thread())
#[<_MainThread(MainThread, stopped 17476)>, <Thread(Thread-1, started 8632)>]
a, b = threading.current_thread()
print(type(a),type(b))
#<class 'threading._MainThread'> <class 'threading.Thread'>
print(len(threading.enumerate()))
#2
'''
返回一个列表数据类型的值,[a,b]:
a:获取当前主线程的线程类,直接输出可以获取主线程的Pid
b:获取当前正在运行的子线程的线程类,直接输出可以获取子进程的name,pid
可以利用该子线程类调用该子线程的方法和属性,从而操作、获取子线程的数据
使用len(threading.enumerate())可以获取当前线程数,包括所有主、子线程
'''
3、activeCount()
/active_count()
#threading.activeCount()或者active_count(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
import threading
print(threading.activeCount())
print(active_count())
4、Lock()类
threading模块中定义了Lock类,可以方便的处理锁定
- 语法:
from threading import Lock
# 生成一个锁对象
mutex = Lock()
4.1 acquire()
加锁
- 语法:
from threading import Lock
# 生成一个锁对象
mutex = Lock()
# 加锁操作
mutex.acquire()
'''
加锁操作应该放在该子线程对数据修改操作的代码前,从而实现在该子线程修改数据时,其他进程无法参入修改操作,保证数据的有序
'''
4.2 release()
释放锁
- 语法:
from threading import Lock
# 生成一个锁对象
mutex = Lock()
# 加锁操作
mutex.acquire()
'''
释放锁操作应该放在子线程对数据修改代码之后,从而能够在该线程对数据修改完毕后,及时释放锁,能让后续其他线程继续对该数据操作
'''
# 释放锁
mutex.release()
5、RLock()
归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。
这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁
'''
RLock与Lock的作用基本一致,但多出了可以重复锁的功能
递归锁的特点:
1.可以被连续的acquire和release
2.但是只能被第一个抢到这把锁,执行上述操作
3.它内部有一个计数器,每acquire一次计数器加一,每release一次计数器减一
4.只要计数器不为0,则其他线程都无法抢该锁
'''
- 语法:
from threading import RLock
mutexA = mutexB = RLock()
mutexA.acquire()
mutexB.acquire()
mutexA.release()
mutexB.release()

浙公网安备 33010602011771号