概述
1、无法利用多核
Python的多线程是无法只用多核进行运算,(多进程可以) 【具体原因是GIL锁,取得GIL锁的进程才能运行,但一个进程的Python只有一个GIL】 【GIL 全局解释器锁】
2、无需通信
在各个子线程中,是可以直接调用到主线程的全局变量等 (可以把各个子线程看作同步运行的普通函数即可)
带来的问题: 假如有多条子线程同时运行,但他们又都会对全局变量A进行修改,且结果不同 这会导致全局变量A的结果随机 【为了放在这种事情发生,必须加一个Lock】
threading:线程模块
threading.Thread 线程类
用法和Process进程类基本差不多 创建的对象也有 strat( )、join( )方法,就连类的构造方法用法都基本差不多
【Thread类构造方法:threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)】 【Process类构造方法:Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)】 所以具体怎么用,去上一篇参考多进程即可
唯一的区别是,线程可以调用全局变量
import threading
def func():
print("子进程")
t = threading.Thread(target=func,args=())
t.start()
t.join()
# 输出
#=========================
子进程
threading.Lock 线程锁类
为了防止“多条子线程同时运行,又同时又对全局变量进行修改” 我们需要使用Lock类,将线程锁起来。
当线程拥有线程锁时,其他线程是无法被运行的,只有当线程锁被释放才能运行。 注意:一个进程只能拥有一个线程锁
类方法: acquire( ):加锁 release( ):释放锁
import threading
import random
import time
def func(x):
time.sleep(random.randint(0,10)*0.1) #给进程一个随机增加运行时长
print("子进程:",x)
for i in range(10):
t = threading.Thread(target=func,args=(i,))
t.start()
print("主线程")
#输出
#===============================
子进程: 5
主线程
子进程: 1
子进程: 6
子进程: 8
子进程: 4
子进程: 9
子进程: 2
子进程: 3
子进程: 0
子进程: 7
分析: 输出结果变得无序,那是因为所有的子线程可以看作是“同步执行的”
假如调用了一个全局变量,而且每个线程在结束前都对全局变量进行不同的修改, 这个变量最后的值将取决于最后一个执行完成的线程 但线程的运行时长是随机的,结果就导致全局变量结果是随机的
Lock的作用: 假如为线程添加一个Lock,当子线程运行时, 就必须等待上一个线程运行到锁被释放,下一个线程才能继续运行
import threading
import random
import time
mylock=threading.Lock()
def func(x):
mylock.acquire() #加线程锁
time.sleep(random.randint(0,10)*0.1)
print("子进程:",x)
mylock.release() #释放线程锁
for i in range(10):
t = threading.Thread(target=func,args=(i,))
t.start()
time.sleep(3)
print("主线程")
# 输出
#================================
子进程: 0
子进程: 1
子进程: 2
子进程: 3
子进程: 4
主线程
子进程: 5
子进程: 6
子进程: 7
子进程: 8
子进程: 9
主线程也是包括在内的, 在上一个线程锁释放之后,所有待运行的进程都会开始运行,包括主线程
+【关于GIL】
GIL是一个进程的全局线程锁,这个线程锁每隔一段时间就会释放一次,用于切换其他线程运行, 以此达到单核CPU运行多个线程的目的 但是是Python中一个进程只有一个GIL,那就意味着, 1、一个进程在同一时间只有一个线程在运行, 2、只是GIL释放和加锁的频率速度很快,让人误以为线程之间是同步进行的 3、Python的线程无法利用多核CPU
在Python2.7之前是可以通过sys.setcheckinterval( )方法来改变GIL的速度,但Python3已经弃用了这个方法
threading.local 本地储存
local类的作用: 将子线程的局部变量储存在,主线程中 使用local对象创建的变量,其他线程不可用(主线程中也一样)
如何使用Local类的对象去创建变量: 绑定
import threading
import random
import time
value_Local = threading.local()# 创建本地储存(用于保存线程的局部变量)
value_Local.x = "不可见" # 主线程的局部变量(子线程不可见)
def func(x):
value_Local.y = x # 在线程中创建局部变量(其他线程不可见)
print("子进程:",value_Local.y)
for i in range(10):
t = threading.Thread(target=func,args=(i,))
t.start()
其实这一块我不是很理解, Local的作用是在主线程中创建一个子线程才能用的局部变量, 但事实上,我可以直接在子线程中创建局部变量。
因此我不是很理解Local的作用。 但我大致猜测,如果尝试在子线程新建一个局部变量, 有可能会导致一些问题,因此把创建的过程放在的主线程中。
这是官方文档的描述: (就这么点内容)