iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Python多线程与同步机制浅析
  • 189
分享到

Python多线程与同步机制浅析

Python多线程Python同步机制 2022-12-22 18:12:50 189人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录线程实现Thread类函数方式继承方式同步机制同步锁Lock条件变量Condition信号量Semaphore事件Event屏障BarrierGIL全局解释器锁线程实现 pyth

线程实现

python中线程有两种方式:函数或者用类来包装线程对象。threading模块中包含了丰富的多线程支持功能:

  • threading.currentThread(): 返回当前线程;
  • threading.enumerate(): 返回包含正在运行的线程列表;
  • threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())等价。

Thread类

通过Thread类来处理线程,类中提供的一些方法:

  • run(): 用以表示线程执行的方法(可重载实现实际功能);
  • start(): 启动线程;
  • join([time]): 等待线程中止(或者超时);
  • isAlive(): 返回线程是否活动;
  • getName(): 返回线程名;
  • setName(): 设置线程名;
  • setDaemon(True):设置为后台进程(必须在start调用前设定)。

函数方式

通过Thread直接构造线程,然后通过start方法启动线程:

threading.Thread(group=None, target=None, name=None, args=(), kwargs=None, *,daemon=None)

各参数说明:

  • group:指定线程隶属的线程组(当前忽略);
  • target:指定线程要调度的目标方法(即实现功能的函数);
  • args:传递给目标方法的参数(以元组的方式);
  • kwargs:传递给目标方法的参数(以字典的方式);
  • daemon:指定线程是否为后台线程。
def simpleRoutine(name, delay):
    print(f"routine {name} starting...")
    time.sleep(delay)
    print(f"routine {name} finished")
if __name__ == '__main__':
    thrOne = threading.Thread(target=simpleRoutine, args=("First", 1))
    thrTwo = threading.Thread(target=simpleRoutine, args=("Two", 2))
    thrOne.start()
    thrTwo.start()
    thrOne.join()
    thrTwo.join()

继承方式

直接继承Thread,创建一个新的子类(主要实现run方法):

class SimpleThread (threading.Thread):
    def __init__(self, name, delay):
        # threading.Thread.__init__(self)
        super().__init__()
        self.name = name
        self.delay = delay
    def run(self):
        print(f"thread {self.name} starting...")
        time.sleep(self.delay)
        print(f"thread {self.name} finished")
if __name__ == '__main__':
    thrOne = SimpleThread("First", 2)
    thrTwo = SimpleThread("Second", 2)
    thrOne.start()
    thrTwo.start()
    thrOne.join()
    thrTwo.join()

同步机制

当多个线程同时修改同一条数据时可能会出现脏数据;所以,就需要线程锁,即同一时刻只允许一个线程执行操作。

同步锁Lock

threading提供了Lock和RLock(可重入锁)两个类,它们都提供了如下两个方法来加锁和释放锁:

  • acquire(blocking=True, timeout=-1):加锁,其中 timeout 参数指定加锁多少秒。
  • release():释放锁。

两种使用锁的方式:

GCount = 0
def PlusOne(locker):
    global gCount
      with locker:
          gCount += 1、
def MinusOne(locker):
    global gCount
      if locker.acquire():
          gCount -= 1
          locker.release()

条件变量Condition

Condition对象内部维护了一个锁(构造时可传递一个Lock/RLock对象,否则内部会自行创建一个RLock)和一个waiting池:

  • 通过acquire获得Condition对象;
  • 当调用wait方法时,线程会释放Condition内部的锁并进入blocked状态,同时在waiting池中记录这个线程;
  • 当调用notify方法时,Condition对象会从waiting池中挑选一个线程,通知其调用acquire方法尝试取到锁。

Condition对象:

__init__(self,lock=None):Condition类总是与一个锁相关联(若不指定lock参数,会自动创建一个与之绑定的RLock对象);

acquire(timeout):调用关联锁的acquire()方法;

release():调用关联锁的release()方法

wait(timeout):线程挂起,直到收到一个notify通知或超时才会被唤醒;必须在已获得锁的前提下调用;

notify(n=1):唤醒waiting池中的n个正在等待的线程并通知它:

  • 收到通知的线程将自动调用acquire()方法尝试加锁;
  • 若waiting池中有多个线程,随机选择n个唤醒;
  • 必须在已获得锁的前提下调用,否则将引发错误。

notify_all():通知所有线程。

class Producer(threading.Thread):
    def __init__(self, cond, storage):
        threading.Thread.__init__(self)
        self.cond = cond
        self.storage = storage
    def run(self):
        label = 1
        while True:
            with self.cond:
                if len(self.storage) < 10:
                    self.storage.append(label)
                    print(f"<- Produce {label} product")
                    label += 1
                    self.cond.notify(2)
                else:
                    print(f"<- storage full: Has Produced {label - 1} product")
                    self.cond.notify_all()
                    self.cond.wait()
                time.sleep(0.4)
class Consumer(threading.Thread):
    def __init__(self, name, cond, storage):
        threading.Thread.__init__(self)
        self.name = name
        self.cond = cond
        self.storage = storage
    def run(self):
        while True:
            if self.cond.acquire():
                if len(self.storage) > 1:
                    pro = self.storage.pop(0)
                    print(f"-> {self.name} consumed {pro}")
                    self.cond.notify()
                else:
                    print(f"-> {self.name} storage empty: no product to consume")
                    self.cond.wait()
                self.cond.release()
                time.sleep(1)

信号量Semaphore

信号量对象内部维护一个计数器:

  • acquire(blocking=True,timeout=None)时减1,当计数为0就阻塞请求的线程;
  • release()时加1,当计数大于0恢复被阻塞的线程;

threading中有Semaphore和BoundedSemaphore两个信号量;BoundedSemaphore限制了release的次数,任何时候计数器的值,都不不能大于初始值(release时会检测计数器的值,若大于等于初始值,则抛出ValueError异常)。

通过Semaphore维护生产(release一个)、消费(acquire一个)量:

# products = threading.Semaphore(0)
def produceOne(label, sem: threading.Semaphore):
    sem.release()
    print(f"{label} produce one")
def consumeOne(label, sem: threading.Semaphore):
    sem.acquire()
    print(f"{label} consume one")

通过BoundedSemaphore来控制并发数量(最多有Semaphore初始值数量的线程并发):

# runner = threading.BoundedSemaphore(3)
def runBound(name, sem: threading.BoundedSemaphore):
    with sem:
        print(f"{name} is running")
        time.sleep(1)
        print(f"{name} finished")

事件Event

事件对象内部有个标志字段,用于线程等待事件的发生:

  • isSet():返回event的状态值;
  • wait():状态为False时,一直阻塞;否则立即返回;
  • set(): 设置状态值为True,激活所有被阻塞的线程;
  • clear():恢复状态值为False。

多线程等待事件发生,然后开始执行:

def waiters(name, evt: threading.Event):
    evt.wait()
    print(f"{name} is running")
    time.sleep(1)
    print(f"{name} finished")
def starting(evt: threading.Event):
    evt.set()
    print("event is set")

屏障Barrier

屏障用于设定等待线程数量,当数量达到指定值时,开始执行:

threading.Barrier(parties, action=None, timeout=None)

屏障属性与方法:

  • wait(timeout=None):等待通过屏障;线程被阻塞,直到阻塞的数量达到parties时,被阻塞的线程被同时全部释放;
  • reset():重置屏障到默认的空状态;
  • abort():将障碍置为断开状态;导致等待的线程引发BrokenBarrierError异常;
  • partier():通过障碍所需的线程数;
  • n_waiting():当前在屏障中等待的线程数;
  • broken():如果屏障处于断开状态,则返回True。
def waitBarrier(name, barr: threading.Barrier):
    print(f"{name} waiting for open")
    try:
        barr.wait()
        print(f"{name} running")
        time.sleep(5)
    except threading.BrokenBarrierError:
        print(f"{name} exception")
    print(f"{name} finished")

GIL全局解释器锁

GIL(Global Interpreter Lock,全局解释器锁);cPython中,某个线程想要执行,必须先拿到GIL(可以把GIL看作是“通行证”)。每次释放GIL锁,线程都要进行锁竞争,切换线程,会消耗资源。

由于GIL锁的存在,python里一个进程永远只能同时执行一个线程(拿到GIL的线程),这就是为什么在多核CPU上,python的多线程效率并不高:

  • CPU密集型代码:由于计算工作多,会很快用完时间片,然后触发GIL的释放与再竞争;
  • IO密集型代码(文件处理、网络爬虫等):多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序执行效率)。

python在使用多线程的时候,调用的是C语言的原生线程:

  • 拿到公共数据
  • 申请GIL
  • python解释器调用os原生线程
  • os操作cpu执行运算
  • 当线程执行时间到后,就进行切换(context switch)

到此这篇关于Python多线程与同步机制浅析的文章就介绍到这了,更多相关Python多线程内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Python多线程与同步机制浅析

本文链接: https://www.lsjlt.com/news/175599.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python多线程与同步机制浅析
    目录线程实现Thread类函数方式继承方式同步机制同步锁Lock条件变量Condition信号量Semaphore事件Event屏障BarrierGIL全局解释器锁线程实现 Pyth...
    99+
    2022-12-22
    Python多线程 Python同步机制
  • Java 多线程同步 锁机制与synchronized深入解析
    打个比方:一个object就像一个大房子,大门永远打开。房子里有很多房间(也就是方法)。这些房间有上锁的(synchronized方法), 和不上锁之分(普通方法)。房门口放着一把钥...
    99+
    2022-11-15
    Java 多线程同步 锁机制
  • Python并行编程多线程锁机制Lock与RLock实现线程同步
    目录什么是锁机制?Lock() 管理线程RLock() 与Lock()的区别什么是锁机制? 要回答这个问题,我们需要知道为什么需要使用锁机制。前面我们谈到一个进程内的多个线程的某些资...
    99+
    2024-04-02
  • c语言多线程同步机制是什么
    C语言中的多线程同步机制是用于确保多个线程之间互斥访问共享资源的一种机制。主要包括互斥锁(Mutex)、条件变量(Condition...
    99+
    2023-08-18
    c语言
  • 如何浅析Java多线程程序的设计机制
    本篇文章为大家展示了如何浅析Java多线程程序的设计机制,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。浅析Java多线程程序设计机制多线程是Java语言的一大特性,多线程就是同时存在N个执行体,按几...
    99+
    2023-06-03
  • Python多进程并发与同步机制超详细讲解
    目录多进程僵尸进程Process类函数方式继承方式同步机制状态管理Managers在《多线程与同步》中介绍了多线程及存在的问题,而通过使用多进程而非线程可有效地绕过全局解释器锁。 因...
    99+
    2022-12-23
    Python多进程并发 Python多进程同步
  • c语言多线程同步机制怎么理解
    C语言多线程同步机制是指在多线程程序中,通过一些机制来保证多个线程之间的协调执行,避免出现竞争条件和死锁等问题。常见的多线程同步机制...
    99+
    2023-09-14
    c语言
  • Java同步与锁机制:保证多线程程序的正确性与可靠性
    随着计算机硬件的快速发展,多核处理器已经成为了主流,多线程编程已经成为了不可避免的趋势。然而,多线程编程也带来了一些问题,例如线程安全问题、死锁问题、竞争条件等等。Java作为一种广泛应用于企业级应用的编程语言,提供了一些同步机制和锁机制...
    99+
    2023-11-09
    同步 numy 日志
  • C++ 如何实现多线程与线程同步
    目录CreateThread 实现多线程:beginthreadex 实现多线程:CreateMutex 互斥锁实现线程同步:通过临界区实现线程同步:Semaphore 基于信号实现...
    99+
    2024-04-02
  • C++多线程中的线程同步与互斥量实例分析
    本篇内容介绍了“C++多线程中的线程同步与互斥量实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!线程同步#include &...
    99+
    2023-06-30
  • Android同步异步任务、多线程及Handler消息处理机制实例分析
    这篇“Android同步异步任务、多线程及Handler消息处理机制实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“A...
    99+
    2023-07-04
  • Java并发编程:同步机制与线程安全探究
    在现代软件开发中,多线程编程已经成为了必不可少的一部分。在Java中,线程的使用非常方便,但是也带来了一些问题,比如线程安全问题。为了解决这些问题,Java提供了一些同步机制。在本文中,我们将探究Java中的同步机制和线程安全。 一、线程...
    99+
    2023-11-09
    同步 numy 日志
  • C#多线程中线程同步的示例分析
    这篇文章将为大家详细讲解有关C#多线程中线程同步的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、前言我们先来看下面一个例子:using System;using Syste...
    99+
    2023-06-29
  • C#多线程之线程同步
    一、前言 我们先来看下面一个例子: using System; using System.Threading; namespace ThreadSynchDemo { cl...
    99+
    2024-04-02
  • Java多线程之线程同步
    volatile 先看个例子 class Test { // 定义一个全局变量 private boolean isRun = true; // 从主线程调...
    99+
    2024-04-02
  • Python线程同步
    from random import randint import threading from time import ctime, sleep data = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h...
    99+
    2023-01-31
    线程 Python
  • python多线程同步售票系统
    目录1、分析过程2、准备过程3、实现过程解决问题场景:假如剩余1000张电影票需要售卖,同时有10家电影App来售卖这1000张电影票。主要的逻辑实现过程是什么,要求使用python...
    99+
    2024-04-02
  • python多线程之间的同步(一)
    引言:       线程之间经常需要协同工作,通过某种技术,让一个线程访问某些数据时,其它线程不能访问这些数据,直到该线程完成对数据的操作。这些技术包括临界区(Critical Section),互斥量(Mutex),信号量(Semapho...
    99+
    2023-01-31
    多线程 python
  • Python多线程机制接口举例分析
    本篇内容介绍了“Python多线程机制接口举例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Python开发工具是一个具有更高层的多线程...
    99+
    2023-06-17
  • Java中的同步机制:如何确保多线程安全?
    在Java中,多线程的应用非常广泛。然而,多线程同时访问共享资源时,很容易引起数据竞争等问题,导致程序出现未知的错误。因此,在多线程编程中,保证线程安全非常重要。Java提供了多种机制来实现线程同步,本文将介绍Java中的同步机制及其应用...
    99+
    2023-11-09
    同步 numy 日志
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作