(python)多线程

前言

        Python 多线程的应用场景通常是在需要同时执行多个 I/O 密集型任务时,以提高程序的效率和性能。

多线程应用场景

  1. 网络爬虫:当需要从多个网站获取数据时,使用多线程可以同时发起多个 HTTP 请求,以加快数据获取速度。

  2. 数据库操作:当需要对大量数据进行读取、写入或修改时,使用多线程可以将任务分成多个子任务,每个子任务在不同的线程中执行,以提高数据库操作效率。

  3. 图像处理:当需要对大量图像进行处理时,使用多线程可以将处理任务分成多个子任务,每个子任务在不同的线程中处理,以提高图像处理速度。

  4. 并发服务器:当需要同时处理多个客户端请求时,使用多线程可以让服务器同时处理多个请求,以提高服务器的吞吐量。

优点

  1. 提高程序的响应速度:在执行多个 I/O 密集型任务时,多线程可以并行执行这些任务,从而提高程序的响应速度。

  2. 简化编程模型:使用多线程可以将复杂的任务分解成多个子任务,并使用多个线程同时执行这些子任务,使得程序结构更清晰。

  3. 资源共享:多线程可以共享同一进程的资源,包括内存空间、文件描述符等,方便数据共享和通信。

  4. 适用于 I/O 密集型任务:适合处理需要大量等待 I/O 操作的任务,如网络请求、文件读写等。

缺点

  1. 全局解释器锁(GIL):Python 的全局解释器锁会导致多线程无法利用多核 CPU,限制了多线程的并行性能。

  2. 线程安全性:多线程编程需要考虑线程安全性问题,如数据竞争、死锁等,增加了程序设计和调试的难度。

  3. 可扩展性受限:由于 GIL 的存在,多线程并不能实现真正的并行执行,因此在 CPU 密集型任务上性能提升有限。

  4. 调试困难:多线程程序更容易出现并发相关的 bug,调试和定位问题相对困难

绕不开的瓶颈-全局解释器锁(GIL)

        全局解释器锁(Global Interpreter Lock,简称 GIL)是 Python 解释器中的一个机制,用于保护共享资源,即 Python 对象的内存管理。在 CPython 解释器中(即官方的 Python 解释器实现),GIL 的存在限制了同一时刻只有一个线程可以执行 Python 字节码。

  1. 线程安全性:由于 Python 的内存管理机制并不是线程安全的,多个线程同时操作 Python 对象可能会导致数据结构损坏或内存泄漏。因此,GIL 通过限制同一时刻只有一个线程执行 Python 字节码,保证了 Python 对象的线程安全。

  2. 简化实现:GIL 简化了 CPython 解释器的实现,减少了对内存管理的复杂度,降低了解释器的开发和维护成本。

 限制和缺点

  1. 性能影响:在 CPU 密集型任务中,GIL 会限制多线程的并发执行,因为同一时刻只有一个线程能够执行 Python 字节码,导致无法充分利用多核 CPU。

  2. 阻碍并行性:由于 GIL 的存在,Python 多线程并不能实现真正的并行执行,只能依靠多进程来充分利用多核 CPU。

  3. 影响扩展性:对于需要高性能并发的应用,如 Web 服务器、科学计算等,GIL 可能成为性能瓶颈,限制了应用的扩展性。

 使用范例

采用多线程

import datetime
import threading
import time


# 定义一个简单的函数,用于在多线程中执行
def task():
    thread_name = 1
    print(f"Thread {thread_name} is starting")

    print(f"Thread {thread_name} is start IO")
    time.sleep(3)  # 模拟耗时操作
    print(f"Thread {thread_name} is finish IO")

    print(f"Thread {thread_name} is start 计算")
    time.sleep(1)  # 模拟耗时操作
    print(f"Thread {thread_name} is finish 计算")

    print(f"Thread {thread_name} is start 输出")
    time.sleep(1)  # 模拟耗时操作
    print(f"Thread {thread_name} is finish 输出")

    print(f"Thread {thread_name} is finishing")


def task2():
    thread_name = 2
    print(f"Thread {thread_name} is starting")

    print(f"Thread {thread_name} is start IO")
    time.sleep(1)  # 模拟耗时操作
    print(f"Thread {thread_name} is finish IO")

    print(f"Thread {thread_name} is start 计算")
    time.sleep(1)  # 模拟耗时操作
    print(f"Thread {thread_name} is finish 计算")

    print(f"Thread {thread_name} is start 输出")
    time.sleep(1)  # 模拟耗时操作
    print(f"Thread {thread_name} is finish 输出")

    print(f"Thread {thread_name} is finishing")


def run():
    task()

    task2()


t1 = datetime.datetime.now()
# 创建多个线程
thread1 = threading.Thread(target=task)
thread2 = threading.Thread(target=task2)

threads = [thread1, thread2]

# 启动并等待所有线程执行完成
for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

cost_time = (datetime.datetime.now() - t1).seconds
print(f"All threads have finished cost_time={cost_time}s")

"""
Thread 1 is starting
Thread 1 is start IO
Thread 2 is starting
Thread 2 is start IO
Thread 2 is finish IO
Thread 2 is start 计算
Thread 2 is finish 计算
Thread 2 is start 输出
Thread 2 is finish 输出Thread 1 is finish IO
Thread 1 is start 计算

Thread 2 is finishing
Thread 1 is finish 计算
Thread 1 is start 输出
Thread 1 is finish 输出
Thread 1 is finishing
All threads have finished cost_time=5s
"""

不采用多线程

# 按顺序运行两个任务
run()

cost_time = (datetime.datetime.now() - t1).seconds
print(f"All threads have finished cost_time={cost_time}s")

"""
Thread 1 is starting
Thread 1 is start IO
Thread 1 is finish IO
Thread 1 is start 计算
Thread 1 is finish 计算
Thread 1 is start 输出
Thread 1 is finish 输出
Thread 1 is finishing
Thread 2 is starting
Thread 2 is start IO
Thread 2 is finish IO
Thread 2 is start 计算
Thread 2 is finish 计算
Thread 2 is start 输出
Thread 2 is finish 输出
Thread 2 is finishing
All threads have finished cost_time=8s
"""

采用多线程的前后对比

 注意:在使用多线程的测试样例中,CPU的资源只有一个,只要不同时使用就不会产生额外的等待时间.否则,需要用线程锁来控制它们对共同资源的使用权.

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Marst·Writer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值