多线程
是python程序中实现多任务的一种方式。线程是程序执行的最小单位。同属一个进程的多个线程共享进程所拥有的的全部资源。
步骤:
a 导入线程模块 import threading
b 创建子线程并指定执行的任务
sing_thread=threading.Thread(target=sing)
c启动线程执行任务
sing_thread.start()
线程执行带有参数的任务时,可用args(以元组方式传参)或 kwargs(以字典方式传参)
import threading # 导入线程模块
import time # 导入时间模块
def sing(x): # 构造函数
for i in range(x):
print("唱歌")
time.sleep(2) # 休眠2秒
def dance(y): # 构造函数
for i in range(y):
print("跳舞")
time.sleep(2) # 休眠2秒
t1=threading.Thread(target=sing, args=(1,)) # 创建子进程t1并指定执行的任务sing,使用args传参
t2 = threading.Thread(target=dance, kwargs={"y": 2}) # 创建子进程t2并指定执行的任务dance,使用kwargs传参
# 启动线程执行任务
t1.start()
t2.start()
使用类来创建多线程
import threading # 导入线程模块
import time # 导入时间模块
class MyThread(threading.Thread): # 定义类,继承自threading.Thread这个基类
def __init__(self, n): # 初始化 ,并传递参数n
super(MyThread, self).__init__()
self.n = n
def run(self): # 启动线程的函数,此种方式创建多线程,函数名只能为run,不能自定义
print('以类的方式创建多线程', self.n)
time.sleep(3)
r1 = MyThread(11) # 实例化对象
r2 = MyThread(22)
r1.start() # 启动线程
r2.start()
多线程的特性 : 主线程会等待所有子线程结束之后才会结束程序
线程锁
为什么需要线程锁?
多个线程对同一个数据进行修改时, 可能会出现不可预料的情况.
例如实现银行转账功能,money += 1 这句其实有三个步骤 money; money+1; money=money+1;假如这三步骤还没完成money-=1的线程就开始执行了,后果可想而知,money的值肯定时乱的
如何实现线程锁?
1. 实例化一个锁对象;
lock = threading.Lock()
2. 操作变量之前进行加锁
lock.acquire()
3. 操作变量之后进行解锁
lock.release()
B站线程锁例子:
import threading # 导入线程模块
def test(): # 构造函数
global x # 全局变量x
lock.acquire() # 申请一把线程锁
x += 1
lock.release() # 操作x之后将线程锁释放
if __name__ == '__main__':
x = 0
res = [] # 定义一个空列表
lock = threading.Lock() # 对线程里面的锁进行实例化
for i in range(100): # 起100个多线程
t = threading.Thread(target=test)
t.start()
res.append(t) # 将线程加入列表
for t in res: # 遍历列表
t.join()
print(x) # 输出线程个数 100
例子2:银行存钱和取钱
import threading
# 银行存钱和取钱
def add(lock):
global money # 生命money为全局变量
for i in range(1000000):
# 2. 操作变量之前进行加锁
lock.acquire()
money += 1 # money; money+1; money=money+1;
# 3. 操作变量之后进行解锁
lock.release()
def reduce(lock):
global money
for i in range(1000000):
# 2. 操作变量之前进行加锁
lock.acquire()
money -= 1
# 3. 操作变量之后进行解锁
lock.release()
if __name__ == '__main__':
money = 0
# 1. 实例化一个锁对象;
lock = threading.Lock()
t1 = threading.Thread(target=add, args=(lock,))
t2 = threading.Thread(target=reduce, args=(lock,))
t1.start()
t2.start()
t1.join()
t2.join()
print("当前金额:", money)
递归锁:锁嵌套时,注意要用 lock= threading.Rlock()
视频网址 69-Python多线程-递归锁_哔哩哔哩_bilibili
import threading
def run1():
global x
lock.acquire()
x += 1
lock.release()
return x
def run2():
global y
lock.acquire()
y += 1
lock.release()
return y
def run3():
lock.acquire()
res1 = run1()
res2 = run2()
print(res1, res2)
lock.release()
if __name__ == '__main__':
x = 0
y = 0
lock = threading.RLock()
for i in range(50):
s = threading.Thread(target=run3())
s.start()
while threading.activeCount() != 1:
print(f"正在运行{threading.activeCount()}个线程")
print("程序运行结束")
作业:在一个线程中,每秒循环输出当前的年月日分秒,与此同时,在另一线程中,实现张三的姓名每2秒打印输出4次结束。注意:都需要使用类和继承来实现功能
不使用类创建:
import threading # 导入线程模块
import time # 导入时间模块
def date(): # 构造方法
while True:
time.sleep(1) # 休眠1秒
print(time.strftime('%Y-%m-%d %X')) # 输出当前时间(年月日分秒)
def run(): # 构造方法
while True:
time.sleep(3) # 休眠3秒
print("张三")
t1 = threading.Thread(target=date) # 创建子线程t1并指定执行的任务date
t2 = threading.Thread(target=run) # 创建子线程t2并指定执行的任务run
t1.start() # 启动线程
t2.start()
使用类创建:
import time # 导入线程模块
import threading # 导入时间模块
class First(threading.Thread): # 定义First类,继承自threading.Thread这个基类
def run(self): # 构造函数
while True:
localtime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) # 输出当前时间
print(localtime)
time.sleep(1) # 休眠一秒
class Second(threading.Thread): # 定义second类,继承自threading.Thread这个基类
def __init__(self, name): # 初始化 ,并传递参数name
super(Second, self).__init__()
self.name = name
def run(self): # 启动线程的函数,此种方式创建多线程,函数名只能为run,不能自定义
for i in range(4): # 张三姓名输出4次后结束
print(self.name)
time.sleep(0.5) # 每打印一次后暂停0.5秒
if __name__ == '__main__':
t1 = First() # 实例化对象
t2 = Second("张三")
t1.start() # 启动线程执行任务
t2.start()