Python多线程编程

1、python并发模型介绍

Python并发编程是指在Python中同时执行多个任务的技术。在传统的程序中,任务是按照顺序依次执行的,而在并发编程中,多个任务可以同时执行。

1.1、python支持的并发模型

  1. 多线程:使用threading模块可以创建和管理多个线程。可以使用Thread类来创建线程,并使用start()方法启动线程。使用join()方法可以等待线程执行完毕。
  2. 使用multiprocessing模块可以创建和管理多个进程。可以使用Process类来创建进程,并使用start()方法启动进程。使用join()方法可以等待进程执行完毕。
  3. 协程:使用asyncio模块可以编写协程代码。使用async关键字定义一个协程函数,使用await关键字可以等待一个协程执行完毕。

本文主要讲述python多线程并发模型。

1.2、与java多线程模型的区别:

  • Python与java都支持基于线程与锁的并发模型。然而,由于GIL(全局解释器锁)的存在,Python在多线程并发编程中性能受限。而Java的多线程性能相对较好,能够充分利用多核处理器的优势。
  • 库和生态系统:Java拥有丰富的并发编程库和框架,如线程池、CountDownLatch、CyclicBarrier等,可以很方便地处理各种并发场景。而Python的并发编程库相对较少,主要的库有threading、multiprocessing和asyncio等,比Java的并发编程库要简单一些。
  • GIL对I/O密集型任务的影响较小:对于I/O密集型的任务,由于线程在等待I/O操作时会释放GIL,因此多线程编程的性能可能会有所提升。这是因为线程在等待I/O时可以让出GIL的控制权,让其他线程有机会执行。

综上所述:Python与java都支持并发编程,然而,python的全局解释器锁对Python的多线程编程产生了一些限制。但Python提供了一些替代方案来实现并发编程,如多进程编程(使用multiprocessing模块)和协程(使用asyncio模块),这些技术可以绕过GIL的限制,实现并发执行。因此,Python的线程模型适用于IO密集型任务,而对于CPU密集型任务,由于GIL的存在,多线程并不一定能够提高性能。对于CPU密集型任务,建议使用多进程并发模型。

2、多线程编程语法

在Python中,可以使用threading模块来实现多线程编程。

以下是threading.Thread类常用的属性和方法:

Thread的属性
name线程名称。可以通过构造函数的name参数指定,也可以通过getName()setName()方法来获取和设置
ident线程的标识符
daemon线程是否为守护线程。守护线程会在主线程结束时自动退出,而非守护线程会等待所有非守护线程执行完毕才会退出
target线程要执行的目标函数
args传递给目标函数的参数,以元组的形式
Thread的方法
start()启动线程,使线程进入就绪状态,可以开始执行target指定的函数。
join(timeout=None)等待线程结束。可以设置timeout参数来设置等待时间
is_alive()判断线程是否处于活动状态
getName()获取线程名称
setName(name)设置线程名称

下面是一个简单的示例:

import threading

def thread_function(name):
    print("Thread {} started".format(name))
    # 线程执行的代码
    print("Thread {} finished".format(name))

# 创建线程对象
thread1 = threading.Thread(target=thread_function, args=("Thread 1",))
thread2 = threading.Thread(target=thread_function, args=("Thread 2",))

# 启动线程
thread1.start()
thread2.start()

# 等待线程执行完毕
thread1.join()
thread2.join()

print("All threads finished")
 

3、多线程编程实例

3.1、多线程下载网页内容(IO密集型,最适合多线程模式)

import threading
import requests

def download(url):
    response = requests.get(url)
    print(f"Downloaded {url}: {len(response.content)} bytes")

# 创建待下载的网页列表
urls = [
    "https://www.baidu.com",
    "https://www.github.com",
    "https://www.python.org"
]

# 创建线程列表
threads = []

# 创建并启动线程
for url in urls:
    thread = threading.Thread(target=download, args=(url,))
    thread.start()
    threads.append(thread)

# 等待所有线程执行完毕
for thread in threads:
    thread.join()

print("All downloads finished")

3.2、线程死锁演示

要懂得线程为什么死锁,我们最好先知道怎样的线程并发会导致死锁。其实,死锁的本质是由于,多条线程以不一致的顺序访问临界资源。

import threading

# 创建互斥锁
lock1 = threading.Lock()
lock2 = threading.Lock()


# 定义线程1
def thread1():
    # 获取锁1
    lock1.acquire()
    print("Thread 1 acquired lock 1")

    # 延迟一段时间,模拟线程1在处理一些任务
    import time
    time.sleep(1)

    # 获取锁2
    lock2.acquire()
    print("Thread 1 acquired lock 2")

    # 释放锁2
    lock2.release()

    # 释放锁1
    lock1.release()


# 定义线程2
def thread2():
    # 获取锁2
    lock2.acquire()
    print("Thread 2 acquired lock 2")

    # 延迟一段时间,模拟线程2在处理一些任务
    import time
    time.sleep(1)

    # 获取锁1
    lock1.acquire()
    print("Thread 2 acquired lock 1")

    # 释放锁1
    lock1.release()

    # 释放锁2
    lock2.release()


# 创建线程1和线程2
t1 = threading.Thread(target=thread1)
t2 = threading.Thread(target=thread2)

# 启动线程1和线程2
t1.start()
t2.start()

# 等待线程1和线程2执行完毕
t1.join()
t2.join()

# 死锁,下面打印将不会输出
print("threads dead lock, both waiting for each other")

线程1已经获取锁1,期待得到锁2;线程2已经获取锁2,期待得到锁1。两条线程以相反的顺序获取竞争资源,互不谦让, 导致死锁。

解决方案之一,可以通过计算两个锁的hash值,确保锁的访问顺序与hash值的大小顺序相同(若hash相同再采用别的指标)。

3.3、生产者消费者模型

每次涉及到并发情景,都喜欢用生产者消费者模式,因为它太经典啦

2个面包师同时生产面包,5个顾客同时取面包。

import threading
import time
import random
from queue import Queue

# 创建一个队列作为生产者和消费者之间的共享缓冲区
buffer = Queue(maxsize=5)
persons = []


class Producer(threading.Thread):
    number = 0

    def __init__(self, id):
        super().__init__()
        self.id = id

    def run(self):
        for _ in range(10):
            buffer.put(Producer.number)
            Producer.number += 1
            print(f"Producer {self.id} produced {Producer.number}")
            time.sleep(random.randint(1, 3))


class Consumer(threading.Thread):
    def __init__(self, id):
        super().__init__()
        self.id = id

    def run(self):
        while True:
            item = buffer.get()
            print(f"Consumer {self.id} consumed {item}")
            time.sleep(random.randint(3, 5))


# 创建并启动生产者线程
for i in range(2):
    producer = Producer(i)
    persons.append(producer)
    producer.start()

# 创建并启动消费者线程
for i in range(5):
    consumer = Consumer(i)
    persons.append(consumer)
    consumer.start()

# 主线程等待生产者和消费者线程执行完毕
for person in persons:
    person.join()

print("All items have been produced and consumed")

3.4、实现CountDownLatch

JavaJUC包里有一个工具类CountDownLatch,用于控制一个或多个线程等待其他线程完成操作后再继续执行。在Python里,我们也可以通过threading模块的Thread类和Condition对象来实现。

import threading


class CountDownLatch:
    def __init__(self, count):
        self.count = count
        self.lock = threading.Condition()

    def count_down(self):
        with self.lock:
            self.count -= 1
            if self.count <= 0:
                self.lock.notify_all()

    def wait(self):
        with self.lock:
            while self.count > 0:
                self.lock.wait()


def worker(latch):
    print("Worker started")
    # 模拟工作时间
    import time
    time.sleep(1)
    print("Worker finished")
    latch.count_down()


if __name__ == "__main__":
    # 创建一个CountDownLatch对象,初始计数为2
    latch = CountDownLatch(2)
    # 创建2个线程并启动
    threading.Thread(target=worker, args=(latch,)).start()
    threading.Thread(target=worker, args=(latch,)).start()
    # 等待所有线程完成工作
    latch.wait()
    print("All workers finished")

3.5、两条线程依次打印ABA或者BAB

主要通过互斥量演示线程间的协助

import threading


class Worker(threading.Thread):
    def __init__(self, name, mutex):
        super().__init__()
        self.name = name
        self.lock = mutex

    def run(self):
        while True:
            with self.lock:
                print(self.name)
                self.lock.notify_all()
                self.lock.wait()


if __name__ == "__main__":
    lock = threading.Condition()
    worker1 = Worker("A", lock)
    worker2 = Worker("B", lock)

    worker1.start()
    worker2.start()

    worker1.join()
    worker2.join()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/593992.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

揭秘大模型应用如何成为当红顶流?

Kimi广告神话背后的关键词战略 如果你生活在中国&#xff0c;你可能不认识ChatGPT&#xff0c;但你一定知道Kimi。无论是学生党还是打工人&#xff0c;都无法避开Kimi的广告。 刘同学在B站上搜教学视频时&#xff0c;弹出了一则软广&#xff0c;上面写着&#xff1a;“作业有…

python学习笔记B-16:序列结构之字典--字典的遍历与访问

下面是字典的访问和遍历方法&#xff1a; d {10:"hello",20:"python",30:"world"} print(d[10],"--",d[20],"--",d[30]) print(d.get(10)) print("以上两种访问方式的区别是&#xff0c;d[key]若键是空值&#xff0c…

代码随想录算法训练营Day12 | 239.滑动窗口最大值、347.前K个高频元素

239.滑动窗口最大值 题目&#xff1a;给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1&#xff1a; 输入&#xff1…

创造价值与回报:创业者的思维格局与商业智慧

在纷繁复杂的商业世界中&#xff0c;有一种信念始终贯穿于无数创业者的心中——那就是创造价值。张磊的这句“只要不断地创造价值&#xff0c;迟早会有回报”道出了创业者的核心思维格局和商业智慧。本文将从创业者的角度&#xff0c;探讨创造价值的重要性&#xff0c;以及如何…

动态炫酷的新年烟花网页代码

烟花效果的实现可以采用前端技术&#xff0c;如HTML、CSS和JavaScript。通过结合动画、粒子效果等技术手段&#xff0c;可以创建出独特而炫目的烟花效果。同时&#xff0c;考虑到性能和兼容性&#xff0c;需要确保效果在各种设备上都能够良好运行。 效果显示http://www.bokequ.…

【分布式系统的金线】——Base理论深度解析与实战指南

关注微信公众号 “程序员小胖” 每日技术干货&#xff0c;第一时间送达&#xff01; 引言 在当今这个数据密集、服务分布的数字时代&#xff0c;设计高效且可靠的分布式系统成为了技术领域的核心挑战之一。提及分布式系统设计的理论基石&#xff0c;CAP理论——即一致性(Cons…

[HNOI2003]激光炸弹

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 二维前缀和板题。 注意从&#xff08;1,1&#xff09;开始存即可&#xff0c;所以每次输入x,y之后&#xff0c;要x,y。 因为m的范围最大为…

uniapp+vue基于移动端的药品进销存系统r275i

最后我们通过需求分析、测试调整&#xff0c;与药品进销存管理系统管理系统的实际需求相结合&#xff0c;设计实现了药品进销存管理系统管理系统。 系统功能需求包含业务需求、功能需求用户需求&#xff0c;系统功能需求分析是在了解用户习惯、开发人员技术和实力等各个因素的前…

美易官方:2024美联储降息,该如何布局

2024美联储降息&#xff0c;该如何布局 #热点引擎计划# 随着2024年美联储降息预期的逐渐升温&#xff0c;全球投资者开始重新考虑其资产配置策略。中金公司认为&#xff0c;面对这一重要的经济事件&#xff0c;投资者需要密切关注市场动态&#xff0c;灵活调整投资策略&#xf…

线性数据结构-手写队列-哈希(散列)Hash

什么是hash散列&#xff1f; 哈希表的存在是为了解决能通过O(1)时间复杂度直接索引到指定元素。这是什么意思呢&#xff1f;通过我们使用数组存放元素&#xff0c;都是按照顺序存放的&#xff0c;当需要获取某个元素的时候&#xff0c;则需要对数组进行遍历&#xff0c;获取到指…

SWMM排水管网水力、水质建模及在海绵与水环境中的应用

随着计算机的广泛应用和各类模型软件的发展&#xff0c;将排水系统模型作为城市洪灾评价与防治的技术手段已经成为防洪防灾的重要技术途径。美国环保局的雨水管理模型&#xff08;SWMM&#xff09;&#xff0c;是当今世界最为著名的排水系统模型。SWMM能模拟降雨和污染物质经过…

触动精灵纯本地离线文字识别插件

目的 触动精灵是一款可以模拟鼠标和键盘操作的自动化工具。它可以帮助用户自动完成一些重复的、繁琐的任务&#xff0c;节省大量人工操作的时间。但触动精灵的图色功能比较单一&#xff0c;无法识别屏幕上的图像&#xff0c;根据图像的变化自动执行相应的操作。本篇文章主要讲解…

利用大语言模型(KIMI)构建智能产品的信息模型

数字化的核心是数字化建模&#xff0c;为一个事物构建数字模型是一件非常繁杂和耗费人工的事情。利用大语言模型&#xff0c;能够轻松地生成设备的信息模型&#xff0c;我们的初步实验表明&#xff0c;只要提供足够的模板&#xff0c;就能够准确地生成设备的数字化模型。 我们尝…

python数据分析——在数据分析中有关概率论的知识

参数和统计量 前言一、总体二、样本三、统计抽样四、随机抽样4.1. 抽签法4.2. 随机数法 五、分层抽样六、整群抽样七、系统抽样八、统计参数九、样本统计量十、样本均值和样本方差十一、描述样本集中位置的统计量11.1. 样本均值11.2. 样本中位数11.3. 样本众数 十二、描述样本分…

电脑怎样才能每天定时自动打开指定文件?定时打开指定文件的方法

要实现电脑每天定时自动打开指定文件&#xff0c;你可以采用多种方法&#xff0c;其中最常见和可靠 的是使用汇帮定时精灵和操作系统的任务计划程序。下面我将为你详细介绍这两种方 法。 方法一&#xff0c;使用汇帮定时精灵【汇帮定时精灵】提供了更多的选项和功能&#xff0c…

Git常用(持续更新)

常用场景&#xff1a; 初始化&#xff1a; git config --global user.name "codelabs" git config --global user.email mycodelabs.com git init git remote add origin https://github.com/username/repository.git git pull origin master 提交&#xff1a; gi…

开源版本管理系统的搭建二:SVN部署及使用

作者&#xff1a;私语茶馆 1. Visual SVN Server部署 SVN Server部署包括&#xff1a; 创建版本仓库创建用户 这些部署是通过VisualSVN Server Manager实现的&#xff0c;如下图&#xff1a; VisualSVN Server Manager&#xff08;安装后自带&#xff09; 1.1.SVN 初始化配…

Fourier 测试时间自适应与多级一致性用于鲁棒分类

文章目录 Fourier Test-Time Adaptation with Multi-level Consistency for Robust Classification摘要方法实验结果 Fourier Test-Time Adaptation with Multi-level Consistency for Robust Classification 摘要 该研究提出了一种名为 Fourier 测试时间适应&#xff08;FTT…

windows驱动开发-内核调度(一)

驱动层面的调度和同步一向是内核中比较困难的部分&#xff0c;和应用层不一样&#xff0c;内核位于系统进程下&#xff0c;所以它的调度和同步一旦出现纰漏&#xff0c;那会影响所有的程序&#xff0c;而内核并不具备对于这种情况下的纠错能力&#xff0c;没有异常手段能够让挂…

workminer之dht通信部分

workminer是通过SSH爆破传播的挖矿木马&#xff0c;感染后会释放xmrig挖矿程序利用主机的CPU挖取北方门罗币。该样本能够执行特定的指令&#xff0c;指令保存在一个配置文件config中&#xff0c;config文件类似于xml文件&#xff0c;里面有要执行的指令和参数&#xff0c;样本中…
最新文章