2022首次更文挑战」。
Python 多线程
python主要是通过thread和threading这两个模块来实现多线程支持。python的thread模块是比较底层的模块,python的threading模块是对thread做了一些封装,可以更加方便的被使用。
创建新的线程有两种方法:
- 通过
threading.Thread()
传递给Thread
对象一个可执行方法(或对象) - 继承
threading.Thread
定义子类并重写run()
方法
threading.Thread()
主要参数:
target
:Callable,可执行方法name
:str,线程名args
:Iterable[Any],可执行方法的参数列表daemon
:bool,这个线程是否是守护线程
示例代码
import randomimport threadingfrom time import sleepdef myPrint(odd: bool): """odd 为 True 输出奇数,否则输出偶数""" for i in range(10): if odd and i % 2 == 1: print(i) elif not odd and i % 2 == 0: print(i) sleep(random.random())t1 = threading.Thread(target= myPrint, args=(True, ))t2 = threading.Thread(target= myPrint, args=(False, ))t1.start()t2.start()复制代码
运行代码,奇数和偶数混合输出,而不是先输出全部奇数,再输出全部偶数。
继承threading.Thread
通过继承threading.Thread
定义子类创建多线程,直接从threading.Thread
继承,然后重写init
方法和run
方法。因为继承了threading.Thread
,调用start
方法时,会自动运行其run
方法中的代码。
示例代码:
class myCPrint(threading.Thread): def __init__(self , odd): super(myCPrint,self).__init__() self.odd = odd def run(self): for i in range(10): if self.odd and i % 2 == 1: print(i) elif not self.odd and i % 2 == 0: print(i) sleep(random.random())c1 = myCPrint(True)c2 = myCPrint(False)c1.start()c2.start()复制代码
运行代码,同样可以看到奇数和偶数混合输出,而不是先输出全部奇数,再输出全部偶数。
Python 多线程存在的问题
Python中的多线程是假的多线程
Python 代码的执行由 Python 虚拟机(解释器)来控制。Python在设计之初就考虑要在主循环中,同时只有一个线程在执行。对 Python 虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁保证同时只有一个线程在运行。在多线程环境中,Python虚拟机按照以下方式执行:
- 设置GIL
- 切换到一个线程并执行
- 线程执行完成或设置为睡眠状态(最多执行100条字节码)
- 解锁GIL
- 重复 1-4
不管有几个核,单位时间多个核只能跑一个线程,然后时间片轮转。
如果需要充分利用多核,可使用multiprocessing
库,创建多进程。