多线程(学习笔记)
1. 基础语法
import threading#导入多线程模块
from time import sleep
def loop(output):
print(f'thread {threading.current_thread().name} is running...')#MainThread
n=0
while n<5:
n=n+1
print(f'thread {threading.current_thread().name}>>{n} {output}')
sleep(1)
print(f'thread {threading.current_thread().name} is end')
print(f'thread {threading.current_thread().name} is running...')
t=threading.Thread(target=loop,name='Loopthread',args=("Hello",))#分配线程任务 !!注意:args接收元组。如果不在"Hello"后面加上逗号,会被误以为是字符串序列。!!
t.start()#启用线程
t.join()#回收线程
print(f'thread {threading.current_thread().name} is end')#MainThread
2. 死循环与CPU占用
import threading
def Endless_loop():#死循环会严重占用CPU资源,是利用率达到100%,但Python中存在全局锁,可以让cpu处理其他线程
print(f'Thread {threading.current_thread().name} is running...')
n=1
while True:
n=n+1
t=threading.Thread(target=Endless_loop,name='Endless_loop')
t.start()
3. 线程锁
balance=0
Lock=threading.Lock()#初始化锁
def func(n):
global balance
balance=balance+n
balance=balance-n
def Lock_test(n):
for i in range(20000000):
Lock.acquire()#请求锁
try:
func(n)
finally:
Lock.release()#释放锁
t1=threading.Thread(target=Lock_test,name='Lock_test',args=(5,))
t2=threading.Thread(target=Lock_test,name='Lock_test',args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)
4. 本地局部变量Local
import threading
# 创建全局ThreadLocal对象:
local_school = threading.local()
def process_student():
# 获取当前线程关联的student:
std = local_school.student
print('Hello, %s (in %s)' % (std, threading.current_thread().name))
def process_thread(name):
# 绑定ThreadLocal的student:
local_school.student = name
process_student()
t1 = threading.Thread(target=process_thread, args=('Alice',), name='Thread-A')
t2 = threading.Thread(target=process_thread, args=('Bob',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()
5. 线程池
如果不设置线程池,可能导致线程的无线增加
from concurrent.futures import ThreadPoolExecutor#导入线程池模块
import threading
from time import sleep
def func(max):
my_sum=0
for i in range(max):
print(threading.current_thread().name+' '+str(i))
my_sum=my_sum+i
return my_sum
pool=ThreadPoolExecutor(max_workers=10)#创建10线程的线程池
thread1=pool.submit(func,20)#向线程池提交任务1
thread2=pool.submit(func,30)#向线程池提交任务2
result1=thread1.result()#获取线程的运行结果
result2=thread2.result()#获取线程的运行结果
#result()会等待线程执行完毕才执行
print(thread1.done())
# 判断future2代表的任务是否结束
print(thread2.done())
# 查看future1代表的任务返回的结果
#done()不会等待线程执行结束才执行,会输出True 或False
print(result1,result2)
pool.shutdown()#关闭线程池
此外,起始有更加巧妙的写法
##
#导入模块等操作
#定义功能函数等操作
##
with ThreadPoolExecutor(max_workers=5) as executor:#使用with...open可以保证线程池自动回收,简化代码
# 提交任务给线程池
thread_ids = [1, 2, 3, 4, 5]
resluts=executor.map(func, thread_ids)#使用map进行分配任务,很巧妙!
print(list(resluts))#解包可迭代对象
6. 总结
-
多线程编程,模型复杂,容易发生冲突,必须用锁加以隔离,同时,又要小心死锁的发生。
-
Python解释器由于设计时有GIL全局锁,导致了多线程无法利用多核。多线程的并发在Python中就是一个美丽的梦。
-
多线程在Python中适合用于IO密集型任务