【进阶16】Python多线程实战案例
一、Python实现多线程的几种方式
_thread:模块提供了基本的线程和互斥锁支持;更底层的的线程管理实现模块
threading:threading模块则通过封装_thread,提供了更加全面的线程使用方法。
_thread案例:
# *coding:utf-8 *
#用_thread启动多个线程完成任务
import _thread
import threading
#板砖的动作
import time
global brick_list
brick_list = ["砖头1", "砖头2", "砖头3", "砖头4", "砖头5", "砖头6", "砖头7","砖头8", "砖头9", "砖头10", "砖头11", "砖头12", "砖头13", "砖头14", "砖头15", "砖头16", "砖头17", "砖头18", "砖头19", "砖头20", "砖头21", "砖头22", "砖头23", "砖头24", "砖头25", "砖头26", "砖头27", "砖头28", "砖头29", "砖头30","砖头31", "砖头32", "砖头33", "砖头34", "砖头35", "砖头36", "砖头37", "砖头38", "砖头39", "砖头40", "砖头41", "砖头42", "砖头43", "砖头44", "砖头45", "砖头46", "砖头47", "砖头48", "砖头49", "砖头50","砖头51", "砖头52", "砖头53", "砖头54", "砖头55", "砖头56", "砖头57", "砖头58", "砖头59", "砖头60","砖头61", "砖头62", "砖头63", "砖头64", "砖头65", "砖头66", "砖头67", "砖头68", "砖头69", "砖头70", "砖头71", "砖头72", "砖头73", "砖头74", "砖头75", "砖头76", "砖头77", "砖头78", "砖头79", "砖头80", "砖头81", "砖头82", "砖头83", "砖头84", "砖头85", "砖头86", "砖头87", "砖头88", "砖头89", "砖头90","砖头91", "砖头92", "砖头93", "砖头94", "砖头95", "砖头96", "砖头97", "砖头98", "砖头99", "砖头100"]
def action():
while True:
if len(brick_list) ==0:
break
brick_list.pop() #搬砖
print(threading.currentThread(),"还剩%s" % (brick_list))
time.sleep(0.1)
def main():
#自己一个人搬
# action()
#请一个人
# _thread.start_new_thread(action,())
#请100个人,多个子进程运行
for i in range(100):
_thread.start_new_thread(action, ())
time.sleep(10)
if __name__ == '__main__':
main()
关键代码解释:
_thread.start_new_thread(action, ()) 启动一个新的线程,执行action函数,
threading案例:
# *coding:utf-8 *
import _thread
import threading
#板砖的动作
import time
global brick_list
brick_list = ["砖头1", "砖头2", "砖头3", "砖头4", "砖头5", "砖头6", "砖头7","砖头8", "砖头9", "砖头10", "砖头11", "砖头12", "砖头13", "砖头14", "砖头15", "砖头16", "砖头17", "砖头18", "砖头19", "砖头20", "砖头21", "砖头22", "砖头23", "砖头24", "砖头25", "砖头26", "砖头27", "砖头28", "砖头29", "砖头30","砖头31", "砖头32", "砖头33", "砖头34", "砖头35", "砖头36", "砖头37", "砖头38", "砖头39", "砖头40", "砖头41", "砖头42", "砖头43", "砖头44", "砖头45", "砖头46", "砖头47", "砖头48", "砖头49", "砖头50","砖头51", "砖头52", "砖头53", "砖头54", "砖头55", "砖头56", "砖头57", "砖头58", "砖头59", "砖头60","砖头61", "砖头62", "砖头63", "砖头64", "砖头65", "砖头66", "砖头67", "砖头68", "砖头69", "砖头70", "砖头71", "砖头72", "砖头73", "砖头74", "砖头75", "砖头76", "砖头77", "砖头78", "砖头79", "砖头80", "砖头81", "砖头82", "砖头83", "砖头84", "砖头85", "砖头86", "砖头87", "砖头88", "砖头89", "砖头90","砖头91", "砖头92", "砖头93", "砖头94", "砖头95", "砖头96", "砖头97", "砖头98", "砖头99", "砖头100"]
def action():
while True:
if len(brick_list) ==0:
break
brick_list.pop() #搬砖
print(threading.currentThread(),"还剩%s" % (brick_list))
time.sleep(0.1)
def main():
#启动两个线程搬砖
# t1=threading.Thread(target=action,args=())
# t2=threading.Thread(target=action,args=())
# t1.start()
# t2.start()
#启动100个线程搬砖
for i in range(100):
temp=threading.Thread(target=action,name="thread"+ str(i),args=())
temp.start()
time.sleep(10)
if __name__ == '__main__':
main()
关键代码解释:
threading.Thread(target=action,name="thread1", args=()) 创建一个线程,这个线程默认没有启动,需要继续调用start()来启动 例如:threading.Thread(target=action,name="thread1", args=()).start() 其中,target用要执行的任务函数,name是线程名,args是传递给执行的任务函数值
二、Threading多线程编程
2.1线程阻塞
Thread().join()
作用:阻塞主线程的运行,让主线程等待所有子线程运行结束之后,再继续运行
# *coding:utf-8 *
import _thread
import threading
#板砖的动作
import time
global brick_list
brick_list = ["砖头1", "砖头2", "砖头3", "砖头4", "砖头5", "砖头6", "砖头7","砖头8", "砖头9", "砖头10", "砖头11", "砖头12", "砖头13", "砖头14", "砖头15", "砖头16", "砖头17", "砖头18", "砖头19", "砖头20", "砖头21", "砖头22", "砖头23", "砖头24", "砖头25", "砖头26", "砖头27", "砖头28", "砖头29", "砖头30","砖头31", "砖头32", "砖头33", "砖头34", "砖头35", "砖头36", "砖头37", "砖头38", "砖头39", "砖头40", "砖头41", "砖头42", "砖头43", "砖头44", "砖头45", "砖头46", "砖头47", "砖头48", "砖头49", "砖头50","砖头51", "砖头52", "砖头53", "砖头54", "砖头55", "砖头56", "砖头57", "砖头58", "砖头59", "砖头60","砖头61", "砖头62", "砖头63", "砖头64", "砖头65", "砖头66", "砖头67", "砖头68", "砖头69", "砖头70", "砖头71", "砖头72", "砖头73", "砖头74", "砖头75", "砖头76", "砖头77", "砖头78", "砖头79", "砖头80", "砖头81", "砖头82", "砖头83", "砖头84", "砖头85", "砖头86", "砖头87", "砖头88", "砖头89", "砖头90","砖头91", "砖头92", "砖头93", "砖头94", "砖头95", "砖头96", "砖头97", "砖头98", "砖头99", "砖头100"]
def action():
while True:
if len(brick_list) ==0:
break
brick_list.pop() #搬砖
print(threading.currentThread(),"还剩%s" % (brick_list))
time.sleep(0.1)
def main():
t1=threading.Thread(target=action,name="1号码农",args=(),daemon=True) #daemon=True为守护进程,当主线程结束也会随之结束
t1.start()
t1.join() #阻塞主线程
if __name__ == '__main__':
main()
2.2 守护线程和非守护线程
获取Thread对象后,通过Thread对象中__init__方法中的daemon参数来设置守护线程和非守护线程,默认是非守护线程。
守护线程:其他线程都运行结束后,守护线程立即结束
非守护线程:无论其他线程有没有运行结束,本线程都必须正常运行结束后才会结束。
import threading
import time
from time import sleep
def action(max):
for i in range(max):
print(threading.currentThread().name+"{}次循环\n".format(i))
time.sleep(1)
def main():
t = threading.Thread(target=action, args=(10000,), name='后台线程')
t.daemon = True #设置为守护线程
# 启动后台线程
t.start()
for i in range(10):
print(threading.current_thread().name+"主线程循环了{}次".format(i))
print("主线程运行结束了")
if __name__ == '__main__':
main()
2.3 线程锁(Lock)和信号量
线程锁(Lock): 为了防止线程与线程之间资源共享导致的线程安全问题,我们可以对访
问的资源加上锁,这个锁就是线程锁。
信号量:信号量是指控制有多少个线程可以访问的相同资源
2.3.1线程锁案例:
Lock对象方法:
acquire() 获取锁
release() 释放锁
import threading
from time import sleep
result = 0
#获取锁对象
lock=threading.Lock()
def add():
global result
lock.acquire() #加锁
for i in range(1000000):
result = result + 1
lock.release() #解锁
print("%s 的resul的结果为:%s" % (threading.current_thread().name,result))
def main():
thread_list = []
for i in range(3):
thread_list.append(threading.Thread(target=add, name="t" + str(i))) # 初始化3个线程,
#并把线程对象添加到thread_list中
for i in range(3):
thread_list[i].start() # 启动thread_list中的3个线程
if __name__ == '__main__':
main()
2.3.2信号量案例:
import threading,time
semaphore=threading.Semaphore(500) #只允许500个人进入地铁站,执行运输任务
def action(counts):
print("{}乘客来到地铁站".format(counts))
semaphore.acquire() # 获得信号量:信号量减一
print("{}乘客已进站".format(counts))
time.sleep(10)
semaphore.release() #释放信号量:信号量加一
print("{}乘客已出站".format(counts))
def main():
for i in range(10000):
t = threading.Thread(target=action, args=(i,))
t.start()
if __name__ == '__main__':
main()
三、队列和线程池
1、队列用法:
from queue import Queue #创建队列 q = Queue(maxsize=10)
队列常见操作方法:
Queue.qsize() 返回队列的大小 Queue.empty() 如果队列为空,返回True,反之False Queue.full() 如果队列满了,返回True,反之False Queue.full 与 maxsize 大小对应 Queue.get([block[, timeout]])获取队列,timeout等待时间 Queue.get_nowait() 相当Queue.get(False) Queue.put(item) 写入队列,timeout等待时间 Queue.put_nowait(item) 相当Queue.put(item, False) Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列 发送一个信号 Queue.join() 实际上意味着等到队列为空,再执行别的操作
案例:
import random
import threading
from queue import Queue
import time
q=Queue(10) #启动一个队列大小是10,能放10个菜
food_menu = ["佛跳墙", "红烧狮子头", "东坡肉", "蚂蚁 上树", "鱼香肉丝", "麻婆豆腐", "鱼子酱", "意大利面", "土豆丝炒肉", "银耳羹", "窝窝头", "糖醋排骨"]
def make_lunch():
"""服务端"""
print("开始做菜")
while True:
if q.full(): #队列满了
print("菜做好了")
q.join() #等待食客吃饭
food_number=random.randint(0,len(food_menu)-1)
q.put(food_menu[food_number]) # 写入队列
print("做了:", food_menu[food_number])
time.sleep(0.5)
def ear_lunch():
time.sleep(10) # 等才做好了再开始吃
while True:
if q.empty(): #队列消息为空
print("吃完了再来一顿")
time.sleep(10)
else:
food_name=q.get() #获取队列消息
print("吃了",food_name)
q.task_done()
def main():
#定义两个消息队列,并开启服务
cooker=threading.Thread(target=make_lunch,args=(),name="cooker")
eater=threading.Thread(target=ear_lunch,args=(),name="cooker")
cooker.start()
eater.start()
if __name__ == '__main__':
main()
2、线程池:
顾名思义就是存放线程的池子,线程池可以控制线程的启动数量,从而达到节省系统资源的目的
作用:可以控制要启动的线程数量。
线程池与信号量Semaphore的区别:
线程池控制的是线程数量,而信号量控制的是并发数量。
超过信号量规定数量的线程,已经被启动了,只是状态是挂起。而线程池中,超过了线
程池规定数量的线程,还没有启动,只能等待启动。
使用方式:
threadpool库是第三方的库,所以必须要进行安装

#线程池案例
import threading
import threadpool
import time
brick_list = ["砖头1", "砖头2", "砖头3", "砖头4", "砖头5", "砖头6", "砖头7","砖头8", "砖头9", "砖头10", "砖头11", "砖头12", "砖头13", "砖头14", "砖头15", "砖头16", "砖头17", "砖头18", "砖头19", "砖头20", "砖头21", "砖头22", "砖头23", "砖头24", "砖头25", "砖头26", "砖头27", "砖头28", "砖头29", "砖头30","砖头31", "砖头32", "砖头33", "砖头34", "砖头35", "砖头36", "砖头37", "砖头38", "砖头39", "砖头40", "砖头41", "砖头42", "砖头43", "砖头44", "砖头45", "砖头46", "砖头47", "砖头48", "砖头49", "砖头50","砖头51", "砖头52", "砖头53", "砖头54", "砖头55", "砖头56", "砖头57", "砖头58", "砖头59", "砖头60","砖头61", "砖头62", "砖头63", "砖头64", "砖头65", "砖头66", "砖头67", "砖头68", "砖头69", "砖头70", "砖头71", "砖头72", "砖头73", "砖头74", "砖头75", "砖头76", "砖头77", "砖头78", "砖头79", "砖头80", "砖头81", "砖头82", "砖头83", "砖头84", "砖头85", "砖头86", "砖头87", "砖头88", "砖头89", "砖头90","砖头91", "砖头92", "砖头93", "砖头94", "砖头95", "砖头96", "砖头97", "砖头98", "砖头99", "砖头100"]
def action(brick):
print(threading.currentThread().name+"搬出了: ",brick)
time.sleep(0.2)
def main():
tp=threadpool.ThreadPool(5) #设置5个线程
requests=threadpool.makeRequests(action,brick_list)
for req in requests: tp.putRequest(req)
tp.wait()
if __name__ == '__main__':
main()
四、tomorrow库:多线程并发测试库
pip install tomorrow
具体案例:
#使用tomorrow来完成“听歌、聊天、吃饭”三件事儿
import time
from random import random
from tomorrow import threads
import threading
@threads(10) # 最多开启10个线程完成任务
def task( task_name):
print( threading.current_thread().name +"正在:", task_name)
if __name__ == '__main__':
task_name_list = ["砖头1", "砖头2", "砖头3", "砖头4", "砖头5", "砖头6", "砖头7","砖头8", "砖头9", "砖头10", "砖头11", "砖头12", "砖头13", "砖头14", "砖头15", "砖头16", "砖头17", "砖头18", "砖头19", "砖头20", "砖头21", "砖头22", "砖头23", "砖头24", "砖头25", "砖头26", "砖头27", "砖头28", "砖头29", "砖头30","砖头31", "砖头32", "砖头33", "砖头34", "砖头35", "砖头36", "砖头37", "砖头38", "砖头39", "砖头40", "砖头41", "砖头42", "砖头43", "砖头44", "砖头45", "砖头46", "砖头47", "砖头48", "砖头49", "砖头50","砖头51", "砖头52", "砖头53", "砖头54", "砖头55", "砖头56", "砖头57", "砖头58", "砖头59", "砖头60","砖头61", "砖头62", "砖头63", "砖头64", "砖头65", "砖头66", "砖头67", "砖头68", "砖头69", "砖头70", "砖头71", "砖头72", "砖头73", "砖头74", "砖头75", "砖头76", "砖头77", "砖头78", "砖头79", "砖头80", "砖头81", "砖头82", "砖头83", "砖头84", "砖头85", "砖头86", "砖头87", "砖头88", "砖头89", "砖头90","砖头91", "砖头92", "砖头93", "砖头94", "砖头95", "砖头96", "砖头97", "砖头98", "砖头99", "砖头100"]
for i in range(0,len(task_name_list)-1):
task(task_name_list[i])
time.sleep(0.2)
本文来自博客园,作者:橘子偏爱橙子,转载请注明原文链接:https://www.cnblogs.com/xfbk/p/17747596.html

浙公网安备 33010602011771号