python 多线程 坑

全局解释器锁(Global Interpreter Lock,GIL)限制

在Python中,一个著名的多线程“坑”就是GIL的存在。因为GIL的存在,即使在多核处理器上,Python的多线程也无法实现真正的并行执行。执行线程时,不管有多少线程,只有一个线程在运行,其它线程都在等待GIL的释放。因此,多线程的效率受到极大的限制。

import threading
import time

def foo():
    for _ in range(1000):
        print("Hello from foo")

def bar():
    for _ in range(1000):
        print("Hello from bar")

thread1 = threading.Thread(target=foo)
thread2 = threading.Thread(target=bar)

start_time = time.time()
thread1.start()
thread2.start()
thread1.join()
thread2.join()
end_time = time.time()
print(f"Time taken with GIL: {end_time - start_time}")

线程安全问题

在访问某些共享数据时,线程可能会发生冲突,导致数据不一致。为避免这一风险,需要使用锁定。(Lock)或者其他同步机制可以保证线程安全。但是使用锁可能会导致新的问题,比如死锁。因此,在设计多线程程序时,管理数据访问是一项技术性的工作。

import threading

class Counter:
    def __init__(self):
        self.value = 0
        self.lock = threading.Lock()

    def increment(self):
        with self.lock:
            self.value += 1
            print(self.value)

def worker(counter):
    for _ in range(1000):
        counter.increment()

counter = Counter()
threads = [threading.Thread(target=worker, args=(counter,)) for _ in range(5)]

for thread in threads:
    thread.start()
for thread in threads:
    thread.join()

线程费用问题

虽然线程是一个轻量级的过程,但与过程相比,创建和管理线程的成本并不低。如果创建大量线程没有限制,Python程序的效率会严重降低。因此,在设计程序时,需要考虑合理的线程数量,或者使用线程池来管理线程。

from concurrent.futures import ThreadPoolExecutor

def task(name):
    print(f"Task {name} is running")

with ThreadPoolExecutor(max_workers=5) as executor:
    tasks = [executor.submit(task, f'task_{i}') for i in range(10)]

# 创建和销毁ThreadPoolExecutor将自动管理线程

任务分配不当

多线程适用于IO密集型任务,因为其他线程可以在线程等待IO操作时继续执行,从而提高效率。但是,如果在CPU密集型任务中使用多线程,效果就不好了。由于CPU资源有限,同时只会有一个线程真正运行,其他的都在等CPU。此时使用多线程可能不如单线程有效。

import threading
import time

def compute_heavy_task():
    # 假定该函数执行一些复杂的计算。
    time.sleep(1)
    return "Task completed"

def execute_tasks():
    threads = []
    for i in range(4):
        thread = threading.Thread(target=compute_heavy_task)
        thread.start()
        threads.append(thread)

    for thread in threads:
        thread.join()

start_time = time.time()
execute_tasks()
end_time = time.time()

print(f"Time taken in a pseudo-CPU-heavy scenario with threading: {end_time - start_time}")

面对各种各样的坑,我们不仅要认识到它们的存在,还要知道如何选择合适的工具。在Python中,当多线程不够或不适用时,我们可以考虑多进程或异步编程(asyncio等)。).

使用多线程确实可以提高性能,但它就像一把双刃剑。如果用得好,可以分担我们的后顾之忧。如果用得不好,可能会带来更多的问题。就像Don一样。 Knuth说:“早期优化是万恶之源”,在真正了解了多线程的优缺点之后,我们才能更加合理地利用它。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.beidandianzhu.com/g/1131.html

(0)
小蓝的头像小蓝
上一篇 2024-12-17
下一篇 2024-12-17

相关推荐

  • 二分查找算法的Python实现

    本文将详细阐述二分查找算法在Python中的实现及其相关内容。 一、二分查找算法介绍 二分查找算法(Binary Search)是一种高效的查找算法,它可以在有序数组中快速定位目标…

    程序猿 2024-12-17
  • Python类型限定

    Python是一种动态类型语言,它允许在运行时为变量分配类型。然而,有时候我们希望对变量的类型做出限定,以便提高程序代码的可读性和维护性。在本文中,我们将详细阐述Python中的类…

    程序猿 2024-12-17
  • Python爬取网页图片

    编程开发工程师的爬虫技术是非常重要的一项技能,其中,使用Python进行网页图片爬取是一个常见的任务。本文将通过几个方面对Python爬取某个网页的图片进行详细阐述。 Python…

    程序猿 2024-12-25
  • 使用Python递归生成二叉树

    在本文中,我们将探讨使用Python递归生成二叉树的方法和技巧。 一、理解二叉树的结构 二叉树是一种树状结构,其中每个节点最多有两个子节点,被称为左子节点和右子节点。它具有以下特点…

    程序猿 2024-12-20
  • Java模板方法讲解

    定义和简单实例 模板方法使子类可以在不改变一个算法结构的情况下,重新定义算法中某些特定步骤的实现。下面是简单示例: publicabstractclassAbstractClass…

  • 以Python打开360浏览器为中心

    Python是一种功能强大的编程语言,在开发中广泛应用。在本文中,我们将探讨如何使用Python打开360浏览器,并提供相应的代码示例。 一、安装Selenium库 首先,我们需要…

    程序猿 2024-12-17
  • Python第四周小测验答案

    本文将围绕Python第四周小测验答案展开详细阐述,包括代码示例和文字解释。 一、题目一 1、问题描述:请编写一个函数,将一个列表中的字符串元素转换为大写。例如,给定列表[&#82…

    程序猿 2024-12-17
  • Python爬虫训练营

    Python爬虫训练营是一个专注于教授Python网络爬虫技术的培训项目。本文将从多个方面对Python爬虫训练营进行详细阐述。 一、课程设置 Python爬虫训练营的课程设置非常…

    程序猿 2024-12-26
  • sum是Python保留字吗

    是的,sum是Python的一个保留字。在Python中,保留字是被特殊保留的一些标识符,它们具有特定的含义,并在编程中有自己的用途。保留字不能作为标识符或变量名使用,否则会引发语…

    程序猿 2024-12-26
  • Python中替换nan值的方法

    在Python编程中,经常会遇到处理缺失数据的情况。其中,常见的一种缺失数据表示方式就是使用NaN(Not a Number)。NaN值的存在会影响数据的分析和建模,因此我们需要对…

    程序猿 2024-12-20

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

分享本页
返回顶部