当前位置: 首页 > article >正文

Python并发

Python是运行在解释器中的语言,查找资料知道,python中有一个全局锁(GIL),在使用多线程(Thread)的情况下,不能发挥多核的优势。而使用多进程(Multiprocess),则可以发挥多核的优势真正地提高效率。

即便在多核心处理器上,使用GIL的解释器也只允许同一时间执行一个线程。总结:(Python是一门伪多线程语言)

为什么有GIL这个东西

GIL存在目的:为了解决多线程之间数据完整性和状态同步问题

GIL存在原因:Python中对象的管理,是使用引用计数器进行的,引用数为0则释放对象(涉及到Python的垃圾回收),简化了Python对共享资源的管理,如 PVM  内存。

import requests
import time
from threading import Thread
from multiprocessing import Process


class MyProcess(multiprocessing.Process):
    """
    define my process must extends Process class
    """

    def run(self):
    """
        define work content
    """
        pass

多线程在IO密集型的操作下似乎也没有很大的优势(也许IO操作的任务再繁重一些就能体现出优势),在CPU密集型的操作下明显地比单线程线性执行性能更差,但是对于网络请求这种忙等阻塞线程的操作,多线程的优势便非常显著了。

多进程无论是在CPU密集型还是IO密集型以及网络请求密集型(经常发生线程阻塞的操作)中,都能体现出性能的优势。不过在类似网络请求密集型的操作上,与多线程相差无几,但却更占用CPU等资源,所以对于这种情况下,可以选择多线程来执行。

import threading, time

class Consumer(threading.Thread):
    def __init__(self):
        pass

    def run(self):
        pass

【Multiprocessing系列】共享资源

    在使用多进程的过程中,最好不要使用共享资源,如果非得使用,则请往下看。Multiprocessing类中共享资源可以使用3种方式,分别是Queue,Array,Manager。这三个都是Multiprocessing自带的组件,使用起来也非常方便。注意:普通的全局变量是不能被子进程所共享的,只有通过Multiprocessing组件构造的数据结构可以被共享。

Queue类

    使用Multiprocessing.Queue类,共享资源(share memory)(只适用Process类)

Array、Value类

    使用Multiprocessing.Array类,共享资源(share memory)(只适用于Process类)

Manager类

使用Multiprocessing.Manager类,共享资源。(可以适用Pool类)

说明:由于windows操作系统下,创建Multiprocessing类对象代码一定要放在main()函数下,而linux不需要,因此这里区分2个版本。

实例目的:父进程在执行子进程的过程中,同步判断一个公共资源值,如果满足条件则结束所有进程。

进程安全变量

num=multiprocessing.Value("d",10.0) # d表示数值,主进程与子进程共享这个value。(主进程与子进程都是用的同一个value)

num=multiprocessing.Array("i",[1,2,3,4,5]) #主进程与子进程共享这个数组

mydict=multiprocessing.Manager().dict() #主进程与子进程共享这个字典

mylist=multiprocessing.Manager().list(range(5)) #主进程与子进程共享这个List

多进程Demo

Pool除了map()外,还有可以返回结果的方式,那就是apply_async().
 
apply_async()中只能传递一个值,它只会放入一个核进行运算,但是传入值时要注意是可迭代的,所以在传入值后需要加逗号, 同时需要用get()方法获取返回值

import multiprocessing as mp


def multicore():
    pool = mp.Pool()
    res = pool.map(job, range(5)) # 定义CPU核数量为5
    print(res)
    res = pool.apply_async(job, (2,)) # 用get获得结果
    print(res.get())

def job(num):
    result = num * num
    return result

ThreadPoolExecutor系列】

多线程并不能充分利用多核处理器。如果需要充分利用多核处理器,可以考虑使用multiprocessing模块进行多进程编程。

  • 从 Python 3.2 开始提供 ThreadPoolExecutor 线程池执行器
  • 创建池的最简单方法是作为上下文管理器,使用 with 语句来管理池的创建和销毁。
  • 如果写过Java程序一定会觉得这个这类相当 的熟悉。
import concurrent.futures

# [rest of code]

if __name__ == "__main__":
    format = "%(asctime)s: %(message)s"
    logging.basicConfig(format=format, level=logging.INFO,
                        datefmt="%H:%M:%S")

    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        executor.map(thread_function, range(3))
#       to_wait = {executor.submit(thread_function, **kwargs): idx for idx in range(total)}

线程安全

# 同步使用Lock
class FakeDatabase:
    def __init__(self):
        self.value = 0
        self._lock = threading.Lock()

    def locked_update(self, name):
        logging.info("Thread %s: starting update", name)
        logging.debug("Thread %s about to lock", name)
        with self._lock:
            logging.debug("Thread %s has lock", name)
            local_copy = self.value
            local_copy += 1
            time.sleep(0.1)
            self.value = local_copy
            logging.debug("Thread %s about to release lock", name)
        logging.debug("Thread %s after release", name)
        logging.info("Thread %s: finishing update", name)

使用Condition进行线程间通信

import threading
import time

# 共享资源
shared_resource = None

# 创建条件变量
condition = threading.Condition()

# 定义一个写线程
class WriterThread(threading.Thread):
    def run(self):
        global shared_resource
        for _ in range(5):
            with condition:
                shared_resource = "Write data"
                print("Writer wrote:", shared_resource)
                condition.notify()  # 通知等待的线程
                condition.wait()  # 等待其他线程通知

# 定义一个读线程
class ReaderThread(threading.Thread):
    def run(self):
        global shared_resource
        for _ in range(5):
            with condition:
                while shared_resource is None:
                    condition.wait()  # 等待写线程通知
                print("Reader read:", shared_resource)
                shared_resource = None
                condition.notify()  # 通知写线程

# 创建写线程和读线程
writer_thread = WriterThread()
reader_thread = ReaderThread()

# 启动线程
writer_thread.start()
reader_thread.start()

# 主线程等待所有子线程结束
writer_thread.join()
reader_thread.join()

print("Main thread exiting")

Thread实现定时器

t = threading.Timer(30.0, my_function)


http://www.kler.cn/a/231981.html

相关文章:

  • mac上使用docker搭建gitlab
  • LlamaIndex+本地部署InternLM实践
  • C++ 中的string类
  • React Native 全栈开发实战班 - 网络与数据之网络请求基础
  • 【C++】深入理解 C++ 优先级队列、容器适配器与 deque:实现与应用解析
  • SpringMVC学习笔记(一)
  • 图数据库 之 Neo4j - 背景介绍(1)
  • Yii特性
  • 第九个知识点:内部对象
  • uniapp中根据图片路径(网络或本地路径)转换为base64
  • 数据结构(C语言)代码实现(八)——顺序栈实现数值转换行编辑程序汉诺塔
  • 深度学习(生成式模型)—— Consistency Models
  • 2.5作业
  • 51单片机精进之路-1点亮led灯
  • c#通过反射完成对象自动映射
  • 《Git 简易速速上手小册》第10章:未来趋势与扩展阅读(2024 最新版)
  • 【Unity】QFramework通用背包系统优化:TipPanel优化
  • 服务器与电脑的区别?
  • 座位预约|座位预约小程序|基于微信小程序的图书馆自习室座位预约管理系统设计与实现(源码+数据库+文档)
  • linux centos安装LibreOffice
  • IS-IS P2P网路类型 地址不在同一子网建立邻居关系
  • 踩坑实录(Third Day)
  • mysql:事务的特性ACID、并发事务(脏读、不可重复读、幻读、如何解决、隔离级别)、undo log和redo log的区别、相关面试题和答案
  • [嵌入式AI从0开始到入土]5_炼丹炉的搭建(基于wsl2_Ubuntu22.04)
  • 今日arXiv最热NLP大模型论文:无需数据集,大模型可通过强化学习与实体环境高效对齐 | ICLR2024
  • 创建一个Vue项目(含npm install卡住不动的解决)