多线程(一)
- 创建多线程
- 多线程特性
- 线程锁
学习视频链接:python多线程
1.创建多线程
p66
多线程类似于同时执行多个不同程序
线程也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行
- 普通方式创建
- 以类的方式创建
#普通方式创建
'''
import threading
import time
def test(x):
print('普通方式创建多线程',x)
time.sleep(2)
if __name__=='__main__':
t1 = threading.Thread(target=test, args=(1,)) # target是要执行的函数名(不是函数),args是函数对应的参数,以元组的形式存在
t2 = threading.Thread(target=test, args=(2,))
t1.start()
t2.start()
'''
#以类的方式创建
import threading
import time
'''
super(Net, self).__init__()
Python中的super(Net, self).__init__()是指首先找到Net的父类(比如是类NNet),
然后把类Net的对象self转换为类NNet的对象,然后“被转换”的类NNet对象调用自己的init函数,
其实简单理解就是子类把父类的__init__()放到自己的__init__()当中,这样子类就有了父类的__init__()的那些东西。
'''
class mythread(threading.Thread): #继承父类threading.Thread
def __init__(self,n):
super(mythread, self).__init__()
self.n=n
def run(self): #重构run函数必须写
print('以类的方式创建多线程',self.n)
time.sleep(2)
if __name__=='__main__':
t1=mythread(1)
t2=mythread(2)
t1.start()
t2.start()
打印如下:
以类的方式创建多线程 1
以类的方式创建多线程 2
2.多线程特性
p67
查看当前线程:threading.current_thread()
查看活动的线程:threading.active_count()
time模块与时间戳和时间相关的重要函数
time.time()
生成当前的时间戳,格式为10位整数的浮点数。
time.strftime()
根据时间元组生成时间格式化字符串。
time.strptime()
根据时间格式化字符串生成时间元组。time.strptime()time.strftime()
为互操作。
time.localtime()
根据时间戳生成当前时区的时间元组。
- 知识点一:
当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行流的最小单元,当设置多线程时,主线程会创建多个子线程,在python中,默认情况下(其实就是setDaemon(False)),主线程执行完自己的任务以后,就退出了,此时子线程会继续执行自己的任务,直到自己的任务结束。 - 知识点二:
当我们使用setDaemon(True)方法,设置子线程为守护线程时,主线程一旦执行结束,则全部线程全部被终止执行可能出现的情况就是,子线程的任务还没有完全执行结束,就被迫停止。 - 知识点三:
此时join的作用就凸显出来了,join所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程在终止
守护线程:
主线程结束,子线程也立马结束。必须在start() 方法调用之前设置
#守护线程
import threading
import time
def run(n):
print('task',n)
time.sleep(1)
print('3s')
time.sleep(1)
print('2s')
time.sleep(1)
print('1s')
if __name__ == '__main__': #主线程
t=threading.Thread(target=run,args=('t1',))
t.setDaemon(True) #设置子线程为守护线程,守护主线程。主线程结束,子线程也立马结束。必须在start() 方法调用之前设置
t.start()
print('end')
打印结果(未加守护线程)
task t1
end
3s
2s
1s
加守护线程
task t1
end
线程同步join
主线程一直等待全部的子线程结束之后,主线程自身才结束
import threading
import time
#join所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程在终止
def run(n):
print('task',n)
time.sleep(1)
print('5s')
time.sleep(1)
print('3s')
time.sleep(1)
print('1s')
if __name__ == '__main__':
t=threading.Thread(target=run,args=('t1',))
# t.setDaemon(True) #把子线程设置为守护线程,必须在start()之前设置
t.start()
t.join() #设置主线程等待子线程结束.主线程一直等待全部的子线程结束之后,主线程自身才结束
print('end')
打印结果(未加join)
taskend
t1
5s
3s
1s
加join
task t1
5s
3s
1s
end
3.线程锁(互斥锁和递归锁)
p68、p69
以下为代码示例:说明(100个线程同时会操作x这个数,如果第五个和第六个同时操作就会乱。加了锁后每次都是一个线程操作x)
#线程锁
'''
#互斥锁
import threading
def run():
global x
lock.acquire() #申请锁
x+=1 #每起一个线程,x就会加1.最后为100
lock.release() #释放锁
if __name__=='__main__':
x=0
res=[]
lock=threading.Lock() #实例化线程锁
for i in range(100): #100个线程
t=threading.Thread(target=run) #t为线程
t.start()
res.append(t)
for t in res:
t.join() #设置主线程等待子线程结束.主线程一直等待全部的子线程结束之后,主线程自身才结束
print(x) #100
'''
#递归锁 RLcok类的用法和Lock类一模一样,但它支持嵌套,在多个锁没有释放的时候一般会使用RLock类
#如下 run3->run1时有两个锁(嵌套) 部分代码
import threading
def run1():
lock.acquire()
global x
x+=1
lock.release()
def run2():
lock.acquire()
global y
y+=1
lock.release()
def run3():
lock.acquire()
r1=run1()
r2=run2()
lock.release()
if __name__=='__main__':
x=0
y=0
lock=threading.RLock
作业:
'''
在一个线程中,每秒循环输出当前的年月日时分秒;
于此同时,在另一个线程中,实现张三的姓名每2秒打印输出4次结束。
注意:都需要使用类和继承实现功能
'''
import threading
import time
class mythread1(threading.Thread): #继承父类threading.Thread
def __init__(self,):
super(mythread1, self).__init__()
def run(self): #重构run函数必须写
while True:
time.sleep(1) #暂停1秒
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) #打印时间
class mythread2(threading.Thread): #继承父类threading.Thread
def __init__(self,name):
super(mythread2, self).__init__()
self.name=name
def run(self): #重构run函数必须写
i=0
while i<4:
time.sleep(2)
print(self.name)
i+=1
if __name__=='__main__':
t1=mythread1()
t2=mythread2('张三')
t1.start()
t2.start()
打印结果:(部分)
2022-01-08 00:43:32
张三
2022-01-08 00:43:33
2022-01-08 00:43:34
张三
2022-01-08 00:43:35
2022-01-08 00:43:36
张三
2022-01-08 00:43:37
2022-01-08 00:43:38
张三
2022-01-08 00:43:39
2022-01-08 00:43:40
2022-01-08 00:43:41
2022-01-08 00:43:42