2022首次更文挑战」。

Python 多线程

python主要是通过thread和threading这两个模块来实现多线程支持。python的thread模块是比较底层的模块,python的threading模块是对thread做了一些封装,可以更加方便的被使用。

创建新的线程有两种方法:

  1. 通过threading.Thread()传递给Thread对象一个可执行方法(或对象)
  2. 继承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虚拟机按照以下方式执行:

  1. 设置GIL
  2. 切换到一个线程并执行
  3. 线程执行完成或设置为睡眠状态(最多执行100条字节码)
  4. 解锁GIL
  5. 重复 1-4

不管有几个核,单位时间多个核只能跑一个线程,然后时间片轮转。

如果需要充分利用多核,可使用multiprocessing库,创建多进程。