精华内容
下载资源
问答
  • 【CSDN编者按】在实际的基准测试下,async (异步)Python比“sync”(同步Python要慢。而更让人担心的是,async框架在负载下会不稳定。 大多数人都认为异步Python的并发程度更高。这意味着对于动态网站或Web ...

    在CSDN公众号上看一篇有趣的翻译文章,搬运过来保存一下。

    【CSDN编者按】在实际的基准测试下,async (异步)Python比“sync”(同步) Python要慢。而更让人担心的是,async框架在负载下会不稳定。
    在这里插入图片描述
    大多数人都认为异步Python的并发程度更高。这意味着对于动态网站或Web API等常见任务,异步能提供更高的性能。
    但遗憾的是,对于Python解释器来说,异步并不能提供加速的推力。
    在现实情境下(请参考下图),异步Web框架的吞吐量(请求/秒)表现更差一些,而响应延迟则差的更多。

    我测试了各种不同的同步和异步Web服务器配置:
    在这里插入图片描述
    P50和P99的响应时间以毫秒为单位,Throughput(吞吐量)以每秒请求量为单位。这个表格按P99排序,我认为这可能是现实世界中最重要的统计信息。

    要注意以下几点:

    1、表现最好的几个都是同步框架

    但Flask的吞吐量比其他的要低

    2、表现最差的几个都是异步框架

    3、异步框架的响应延迟方面也差得多

    4、基于uvloop的循环比内置的asyncio循环更好

    因此,如果非要用asyncio,请选择uvloop

    这些基准测试真的具有代表性吗?

    我认为的确如此。我尽力使它们贴近现实情况了,使用的架构是这个:
    在这里插入图片描述
    测试的应用程序通过随机key查询数据库某行,并将值以JSON的形式返回。完整的源代码可在github上找到。

    (链接:https://github.com/calpaterson/python-web-perf)

    为什么工作进程数(worker count)不一样?

    我用来确定最佳工作进程数的原则十分简单:对于每个框架, 我都是从一个开始,连续增加数量,直到性能变差。

    异步和同步框架之间的最佳工作程序数量有所不同,其中的原因也显而易见。异步框架由于其IO并发性,单个工作进程就能让一个CPU饱和。

    而同步工作进程的情况就不一样了:当他们执行IO时会进入阻塞,直到IO完成。因此,他们需要有足够的工作进程,来确保在负载下所有CPU核心始终处于满负荷状态。

    更多这方面的信息,请参见gunicorn文档:

    通常,我们建议(2 x $ num_cores)+ 1作为启示的worker数量。尽管不是太科学,但这个公式是基于这个假设的:对于一个给定的内核,当一个worker在处理请求时,另外一个 worker可以从套接字中读写数据。
    (文档链接:https://docs.gunicorn.org/en/stable/design.html#how-many-workers)

    机器规格

    我在Hetzner的CX31机器类型上运行了基准测试,它是一个4 vCPU / 8 GB内存的机器,运行在Ubuntu 20.04上。在另一个(较小的)虚拟机上运行了施压程序。

    为什么异步表现更糟糕?

    吞吐量

    对于吞吐量(即:请求/秒),主要影响因素不是异步和同步,而是用本地代码替换了多少Python代码。简而言之,你能替换的对性能敏感的Python代码越多,性能就越好。这是历史悠久的Python性能策略(另请参考numpy)。

    Meinheld和UWSGI(每个约5.3k请求量/秒)包含了大量C语言代码。而标准 Gunicorn(约 3.4k请求量/秒)是纯 Python。

    Uvicorn + Starlette(~4.9k请求/秒)比 AIOHTTP 的默认服务器(~4.5k请求量/秒)替换了更多的 Python 代码(尽管 AIOHTTP 也安装了它的可选 “加速”)。

    延迟

    在延迟方面,问题则是更深层次的。与传统的同步部署相比,在负载下,异步的表现很差,并且延迟开始急剧上升。

    为什么会出现这种情况呢?在异步Python中,多线程合作式(co-operative)的,简单来说意思就是线程不会被中央控制器(例如内核)打断,而必须主动把执行时间分配给其他人。在asyncio中,执行取决于三个语言关键字:await,async for和async with。

    这意味着执行时间不是“公平”分配的,并且一个线程在工作时可能会无意间让另一个线程得不到CPU时间而饿死。这就是延迟较为不稳定的原因。

    相形之下,诸如UWSGI之类的传统同步Python Web服务器,使用的是内核调度程序的抢占式(pre-emptive)多进程,其工作原理是通过定期从执行中换出进程来确保公平性。这意味着时间分配更加公平,并且延迟差异也较小。

    为什么其他基准测试显示的结果不同?

    大多数其他基准测试(尤其是那些来自异步框架作者的!)根本没有为同步框架配置足够的工作进程数。这意味着,大部分实际上可用的CPU时间这些同步框架根本无法接触到。

    这是Vibora项目的基准示例。(我没有测试这个框架,因为它不是特别流行。)在这里插入图片描述
    另一个问题是,许多基准测试降低了延迟的优先级,而偏向吞吐量的结果(例如,Vibora甚至没有提及延迟)。然而,吞吐量可以通过增加机器来优化,但负载下的延迟却不能。

    只有在延迟处于可接受范围内时,增加吞吐量才真的有意义。

    进一步的推理,假设和传闻

    虽然基准测试在设计方面尽量接近现实,但也仍然比现实生活中的工作负载要单调得多—— 所有的请求都会做一个数据库查询,都会用这个查询做同样的事情。真实的应用场景通常会有更丰富的变化,会有一些慢的,也会有一些快的操作,一些请求做了很多 IO,另外一些使用了很多 CPU。似乎有理由假设(根据我的经验也是如此),在真实的应用中,延迟变化实际上要高得多。

    我的直觉是,在真实场景下,异步应用程序的性能会出现更多的问题。公开的传闻与我这个想法一致:

    Dan McKinley曾经分享过他在Etsy管理一个基于Twisted系统的经历。似乎那个系统遭受了延迟变大的困扰:

    [Twisted的顾问]说,尽管Twisted在整体吞吐量方面表现很好,但比较偏的请求可能会遭遇严重的延迟。这对于[Etsy的系统]来说是个问题,因为PHP前端使用它的方式是每个Web请求访问上百/上千次。

    SQLAlchemy的作者Mike Bayer几年前写了《异步Python和数据库》,其中他从一个稍微不同的角度考虑了异步的问题。他还进行了基准测试,发现asyncio效率较低。

    (链接:https://techspot.zzzeek.org/2015/02/15/asynchronous-python-and-databases/)

    Rachel by the Bay撰写了一篇题为“我们必须谈论Python,Gunicorn,Gevent”的文章,其中她描述了基于gevent配置所产生的操作混乱。我在生产中使用gevent时也曾经遇到过麻烦(尽管与性能无关)。

    (链接:https://rachelbythebay.com/w/2020/03/07/costly/)

    我还要提到的另一件事是,在设置这些基准测试的过程中,每个异步实现最终都以一种烦人的方式挂了。

    Uvicorn的父进程在不终止其子进程的情况下就退出了,这意味着我不得不去寻找那些仍然留在端口8001上的子进程。有那么一次,AIOHTTP提出了一个内部严重报错,这个报错与文件描述符有关,但它并没有退出(因此任何进程监控脚本都不会重启它——这简直是犯了重大错误!)。Daphne在本地也遇到了麻烦,但我忘了具体是怎么回事了。

    所有这些错误都是暂时性的,可以使用SIGKILL轻松解决。但是事实仍然是,我不想在生产环境中负责基于这些库的代码。相比之下,我在用Gunicorn或UWSGI时就没有出现过任何问题——除了一点,我真的不喜欢UWSGI 在应用没有正确加载时不会退出这个特性。

    我的建议:出于性能方面的考虑,仅使用普通的同步Python即可,但尽可能使用native代码。对于Web服务器,如果吞吐量至关重要,那么值得考虑一下使用Flask以外的框架,但即使是UWSGI下的Flask也具有最佳延迟特性。

    感谢我的朋友Tudor Munteanu帮我仔细检查了文中的数据。

    参考

    Flask的原始作者已经发表了几篇文章,表达了他对异步的担忧,首先是《我不理解Python的Asyncio》,这篇对异步技术做了很好的解释,最近又发表了《我没有感受到异步的压力》一文,里面说:

    async / await很棒,但是它鼓励大家写的东西会在过载时出现灾难性的结果

    (链接:https://lucumr.pocoo.org/2016/10/30/i-dont-understand-asyncio/

    https://lucumr.pocoo.org/2020/1/1/async-pressure/)

    《你的函数是什么颜色?》一文中解释了为什么一个语言如果同时有同步和异步,会使开发过程更加痛苦的一些原因。

    (链接:https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/)

    函数着色是Python中的一个大问题,可悲的是,现在的社区被划分为写同步代码的人和写异步代码的人——他们不能共享相同的库。更糟糕的是,某些异步库还不能与其他异步库兼容,所以异步Python社区甚至更加分裂了。

    Chris Wellons最近写了一篇文章,文中还谈到了延迟问题和asyncio标准库中的一些注脚。遗憾的是,这种问题恰恰能使异步程序更加难以处理。

    (链接:https://nullprogram.com/blog/2020/05/24/)

    另外,Nathaniel J.Smith认为异步库的概念是错误的。我的担忧是,如果辩论PEP规范的那些大牛们都搞不清,那么像我这样的普通开发者还有希望吗?

    作者简介:

    Cal Paterson,独立软件工程师,主要工作语言为Python,对数据库和通讯方面的后端问题兴趣颇深,现居伦敦。

    原文链接:

    http://calpaterson.com/async-python-is-not-faster.html

    本文为CSDN翻译文章,转载请注明出处。

    CSDN官方公众号搬运,原贴链接:https://mp.weixin.qq.com/s?__biz=MjM5MjAwODM4MA

    展开全文
  • Python 线程同步

    2010-03-15 16:49:00
    有时需要更复杂的线程同步,例如只在发生某些事件时才访问一个临界区(例如当某个数值改变时)。这就要使用“条件变量”。  条件变量用 threading.Condition 类创建   mycondition = threading.Condition...

    多个执行线程经常要共享数据,如果仅仅读取共享数据还好,但是如果多个线程要修改共享数据的话就可能出现无法预料的结果。

        假如两个线程对象t1t2 都要对数值num=0 进行增1运算,那么t1t2 都各对num 修改10 次的话,那么num 最终的结果应该为20 。但是如果当t1 取得num 的值时(假如此时num0 ),系统把t1 调度为“sleeping ”状态,而此时t2 转换为“running ”状态,此时t2 获得的num 的值也为0 ,然后他把num+1 的值1 赋给num 。系统又把t2 转化为“sleeping ”状态,t1 为“running ”状态,由于t1 已经得到num 值为0 ,所以他也把num+1 的值赋给了num1 。本来是2 次增1 运行,结果却是num 只增了1 次。类似这样的情况在多线程同时执行的时候是有可能发生的。所以为了防止这类情况的出现就要使用线程同步机制。

        最简单的同步机制就是“锁”

        锁对象用threading.RLock 类创建

        mylock = threading.RLock()

        如何使用锁来同步线程呢?线程可以使用锁的acquire() (获得)方法,这样锁就进入“locked ”状态。每次只有一个线程可以获得锁。如果当另一个线程试图获得这个锁的时候,就会被系统变为“blocked ”状态,直到那个拥有锁的线程调用锁的release() (释放)方法,这样锁就会进入“unlocked ”状态。“blocked ”状态的线程就会收到一个通知,并有权利获得锁。如果多个线程处于“blocked ”状态,所有线程都会先解除“blocked ”状态,然后系统选择一个线程来获得锁,其他的线程继续沉默(“blocked ”)。

    import threading
    mylock = threading.RLock()
    class mythread(threading.Thread)
        ...
        def run(self ...):
            ...     #此处 不可以 放置修改共享数据的代码
            mylock.acquire()
            ...     #此处 可以 放置修改共享数据的代码
            mylock.release()
            ...    
    #此处 不可以 放置修改共享数据的代码

        我们把修改共享数据的代码称为“临界区”,必须将所有“临界区”都封闭在同一锁对象的acquire()release() 方法调用之间。

        锁只能提供最基本的同步级别。有时需要更复杂的线程同步,例如只在发生某些事件时才访问一个临界区(例如当某个数值改变时)。这就要使用“条件变量”。

        条件变量用threading.Condition 类创建

        mycondition = threading.Condition()

        条件变量是如何工作的呢?首先一个线程成功获得一个条件变量后,调用此条件变量的wait() 方法会导致这个线程释放这个锁,并进入“blocked ”状态,直到另一个线程调用同一个条件变量的notify() 方法来唤醒那个进入“blocked ”状态的线程。如果调用这个条件变量的notifyAll() 方法的话就会唤醒所有的在等待的线程。

        如果程序或者线程永远处于“blocked ”状态的话,就会发生死锁。所以如果使用了锁、条件变量等同步机制的话,一定要注意仔细检查,防止死锁情况的发生。对于可能产生异常的临界区要使用异常处理机制中的finally 子句来保证释放锁。等待一个条件变量的线程必须用notify() 方法显式的唤醒,否则就永远沉默。保证每一个wait() 方法调用都有一个相对应的notify() 调用,当然也可以调用notifyAll() 方法以防万一。

    展开全文
  • python线程同步

    千次阅读 2012-11-20 17:16:32
    假设两个线程对象t1和t2都要对num=0进行增1运算,t1和t2都各对num修改10次,num的最终的结果应该为20。但是由于是多线程访问,有可能出现下面情况:在num=0时...系统此时把t1调度为”sleeping”状态,把t2转换为”r

    转自:http://www.cnblogs.com/tqsummer/archive/2011/01/25/1944771.html

    假设两个线程对象t1和t2都要对num=0进行增1运算,t1和t2都各对num修改10次,num的最终的结果应该为20。但是由于是多线程访问,有可能出现下面情况:在num=0时,t1取得num=0。系统此时把t1调度为”sleeping”状态,把t2转换为”running”状态,t2页获得num=0。然后t2对得到的值进行加1并赋给num,使得num=1。然后系统又把t2调度为”sleeping”,把t1转为”running”。线程t1又把它之前得到的0加1后赋值给num。这样,明明t1和t2都完成了1次加1工作,但结果仍然是num=1。

      上面的case描述了多线程情况下最常见的问题之一:数据共享。当多个线程都要去修改某一个共享数据的时候,我们需要对数据访问进行同步。

    1、  简单的同步

    最简单的同步机制就是“锁”。锁对象由threading.RLock类创建。线程可以使用锁的acquire()方法获得锁,这样锁就进入“locked”状态。每次只有一个线程可以获得锁。如果当另一个线程试图获得这个锁的时候,就会被系统变为“blocked”状态,直到那个拥有锁的线程调用锁的release()方法来释放锁,这样锁就会进入“unlocked”状态。“blocked”状态的线程就会收到一个通知,并有权利获得锁。如果多个线程处于“blocked”状态,所有线程都会先解除“blocked”状态,然后系统选择一个线程来获得锁,其他的线程继续沉默(“blocked”)。

    Python中的thread模块和Lock对象是Python提供的低级线程控制工具,使用起来非常简单。如下例所示:

    import thread  
    import time  
    mylock = thread.allocate_lock()  #Allocate a lock  
    num=0  #Shared resource  
      
    def add_num(name):  
        global num  
        while True:  
            mylock.acquire() #Get the lock   
            # Do something to the shared resource  
            print 'Thread %s locked! num=%s'%(name,str(num))  
            if num >= 5:  
                print 'Thread %s released! num=%s'%(name,str(num))  
                mylock.release()  
                thread.exit_thread()  
            num+=1  
            print 'Thread %s released! num=%s'%(name,str(num))  
            mylock.release()  #Release the lock.  
      
    def test():  
        thread.start_new_thread(add_num, ('A',))  
        thread.start_new_thread(add_num, ('B',))  
      
    if __name__== '__main__':  
        test()  

    Python thread的基础上还提供了一个高级的线程控制库,就是之前提到过的threadingPythonthreading module是在建立在thread module基础之上的一个module,在threading module中,暴露了许多thread module中的属性。在thread module中,python提供了用户级的线程同步工具“Lock”对象。而在threading module中,python又提供了Lock对象的变种: RLock对象。RLock对象内部维护着一个Lock对象,它是一种可重入的对象。对于Lock对象而言,如果一个线程连续两次进行acquire操作,那么由于第一次acquire之后没有release,第二次acquire将挂起线程。这会导致Lock对象永远不会release,使得线程死锁。RLock对象允许一个线程多次对其进行acquire操作,因为在其内部通过一个counter变量维护着线程acquire的次数。而且每一次的acquire操作必须有一个release操作与之对应,在所有的release操作完成之后,别的线程才能申请该RLock对象。下面来看看如何使用threading的RLock对象实现同步。

    下面来看看如何使用threadingRLock对象实现同步。

    import threading  
    mylock = threading.RLock()  
    num=0  
       
    class myThread(threading.Thread):  
        def __init__(self, name):  
            threading.Thread.__init__(self)  
            self.t_name = name  
              
        def run(self):  
            global num  
            while True:  
                mylock.acquire()  
                print '\nThread(%s) locked, Number: %d'%(self.t_name, num)  
                if num>=4:  
                    mylock.release()  
                    print '\nThread(%s) released, Number: %d'%(self.t_name, num)  
                    break  
                num+=1  
                print '\nThread(%s) released, Number: %d'%(self.t_name, num)  
                mylock.release()  
                  
    def test():  
        thread1 = myThread('A')  
        thread2 = myThread('B')  
        thread1.start()  
        thread2.start()  
       
    if __name__== '__main__':  
        test()  
    我们把修改共享数据的代码成为“临界区”。必须将所有“临界区”都封闭在同一个锁对象的 acquirerelease之间。



    展开全文
  • Python 线程同步与互斥

    千次阅读 2015-11-04 18:38:23
    在操作系统中,指一个时间段内有几个程序都处于已启动到运行结束之间的状态,并且这几个程序都是在同一个处理机上运行的,但任一个时间点却只有一个程序在处理机上执行。 注意并发与并行并不是同一个概念。并发是指...

    什么是并发?

    在操作系统中,指一个时间段内有几个程序都处于已启动到运行结束之间的状态,并且这几个程序都是在同一个处理机上运行的,但任一个时间点却只有一个程序在处理机上执行。
    注意并发与并行并不是同一个概念。并发是指一个时间段内同时运行,表示的是一个区间,而并行是指在同一个时间点上都在运行,是一个点,并且并发在同一时间点上只能有一个程序在运行。
    在实际应用中,多个线程往往会共享一些数据(如:内存堆栈、串口、文件等),并且线程间的状态和行为都是互相影响的。并发线程的两种关系:同步与互斥。

    线程同步与互斥

    互斥:线程之间通过对资源的竞争,所产生的相互制约的关系,就是互斥关系。这类线程间主要的问题就是互斥和死锁的问题。

    同步:进程之间不是相互排斥的关系,而是相互依赖的关系。换句话说,就是多进程共享同一临界资源时,前一个进程输出作为后一个进程的输入,当第一个进程没有输出时,第二个进程必须等待。因为当多个线程共享数据时,可能会导致数据处理出错,因此线程同步主要的目的就是使并发执行的各线程之间能够有效的共享资源和相互合作,从而使程序的执行具有可再现性。
    共享数据指的是并发执行的多个线程间所操作的同一数据资源。
    出现共享资源访问冲突的实质就是线程间没有互斥的使用共享资源,也就是说并发执行过程中,某一个线程正在对共享资源访问时,比如写,此时其它的线程就不能访问这个共享数据,直到正在访问它的线程访问结束。避免互斥,我们通过对共享资源进行加锁操作来避免访问冲突。当有线程拿到访问这个共享数据的权限时,就对其加一把锁,这样别的线程由于得不到访问的锁,所以不能访问,直到线程释放了这把锁,其它线程才能访问。
    线程将的同步与互斥,是为了保证所共享的数据的一致性。

    关于线程互斥的实例:

    import threading
    import time
    
    data = 0
    lock = threading.Lock()#创建一个锁对象
    
    def func() :
      global data
      print "%s acquire lock...\n" %threading.currentThread().getName()
      if lock.acquire() :
        print "%s get lock...\n" %threading.currentThread().getName()
        data += 1 #must lock
        time.sleep(2)#其它操作
        print "%s release lock...\n" %threading.currentThread().getName()
    
        #调用release()将释放锁
        lock.release()
    
    startTime = time.time()
    t1 = threading.Thread(target = func)
    t2 = threading.Thread(target = func)
    t3 = threading.Thread(target = func)
    t1.start()
    t2.start()
    t3.start()
    t1.join()
    t2.join()
    t3.join()
    
    endTime = time.time()
    print "used time is", endTime - startTime
    

    执行结果:

    Thread-1 acquire lock...
    
    Thread-1 get lock...
    Thread-2 acquire lock...
    
    Thread-3 acquire lock...
    
    
    Thread-1 release lock...
    
    Thread-2 get lock...
    
    Thread-2 release lock...
    
    Thread-3 get lock...
    
    Thread-3 release lock...
    
    used time is 6.0039999485
    

    上边的实例创建了3个线程t1、t2和t3同步执行,三个线程都访问全局变量data,并改变它的值。当第一个线程t1请求锁成功后,开始访问共享数据data,第二个线程t2和t2也开始请求锁,但是此时t1还没有释放锁,所以t2、t3处于等待锁状态,直到t1调用lock.release()释放锁以后,t2才得到锁,然后执行完释放锁,t3才能得到锁。这样就保证了这三个线程共享数据data的一致性和同步性。并且这三个线程是并发执行的,没有人为控制其获得锁的顺序,所以它们执行的顺序也是不定的。
    注意:
    调用acquire([timeout])时,线程将一直阻塞,直到获得锁定或者直到timeout秒后返回是否获得锁。

    关于线程同步的一个经典实例:生产者与消费者

    #coding=utf-8  
    from Queue import Queue   #队列类 
    import random    
    import threading    
    import time      
    
    #生成者线程
    class Producer(threading.Thread):    
        def __init__(self, t_name, queue): 
            #调用父线程的构造方法。
            threading.Thread.__init__(self, name=t_name)    
            self.data=queue  
    
        def run(self):    
            for i in range(5):    
                print "%s: %s is producing %d to the queue!\n" %(time.ctime(), self.getName(), i)  
                self.data.put(i)#向队列中添加数据    
                #产生一个0-2之间的随机数进行睡眠
                time.sleep(random.randrange(10)/5)    
            print "%s: %s finished!" %(time.ctime(), self.getName()) 
    #消费者线程 
    class Consumer(threading.Thread):    
        def __init__(self, t_name, queue):    
            threading.Thread.__init__(self, name=t_name)  
            self.data=queue  
    
        def run(self):    
            for i in range(5):    
                val = self.data.get()#从队列中取出数据    
                print "%s: %s is consuming. %d in the queue is consumed!\n" %(time.ctime(), self.getName(), val)
                time.sleep(random.randrange(10))  
    
            print "%s: %s finished!" %(time.ctime(), self.getName())  
    #Main thread    
    def main():    
        queue = Queue()#创建一个队列对象(特点先进先出)    
        producer = Producer('Pro.', queue)#生产者对象    
        consumer = Consumer('Con.', queue)#消费者对象
        producer.start()    
        consumer.start()  
        producer.join()    
        consumer.join()  
        print 'All threads terminate!'  
    
    if __name__ == '__main__':  
        main()
    

    通过使用Python的队列类,进行线程同步处理时,就不需要考虑加锁的问题了,因为队列内部会自动加锁进行处理。

    死锁

    如果程序中多个线程相互等待对方持有的锁,而在得到对方的锁之前都不释放自己的锁,由此导致了这些线程不能继续运行,这就是死锁。
    死锁的表现是:程序死循环。
    防止死锁一般的做法是:如果程序要访问多个共享数据,则首先要从全局考虑定义一个获得锁的顺序,并且在整个程序中都遵守这个顺序。释放锁时,按加锁的反序释放即可。
    所以必须是有两个及其以上的的并发线程,才能出现死锁,如果是多于2个线程之间出现死锁,那他们请求锁的关系一定是形成了一个环,比如A等B的锁,B等C的锁,C等A的锁。

    实例:

    #coding=utf-8
    import threading  
    import time
    
    lock1 = threading.Lock()  
    lock2 = threading.Lock()  
    print lock1, lock2
    class T1(threading.Thread):  
        def __init__(self, name):  
            threading.Thread.__init__(self)  
            self.t_name = name  
    
        def run(self):  
            lock1.acquire()  
            time.sleep(1)#睡眠的目的是让线程2获得调度,得到第二把锁
            print 'in thread T1',self.t_name
            time.sleep(2) 
            lock2.acquire() #线程1请求第二把锁  
            print 'in lock l2 of T1'  
            lock2.release()      
            lock1.release() 
    
    class T2(threading.Thread):  
        def __init__(self, name):  
            threading.Thread.__init__(self)  
            self.t_name = name  
    
        def run(self):  
            lock2.acquire()  
            time.sleep(2)#睡眠的目的是让线程1获得调度,得到第一把锁
            print 'in thread T2',self.t_name
            lock1.acquire() #线程2请求第一把锁
            print 'in lock l1 of T2'
            lock1.release() 
            lock2.release() 
    
    def test():  
        thread1 = T1('A')  
        thread2 = T2('B')  
        thread1.start()  
        thread2.start()  
    
    if __name__== '__main__':  
        test()  
    

    上面的实例中,在两个线程thread1和thread2分别得到一把锁后,然后在线程1中请求线程2得到的那把锁,线程2中请求在线程1中得到的那把锁,由于两个线程都在请求对方的锁,但却没有一方释放它们的锁,所以就会出现死锁的情况,程序执行后就会出现下面的结果:
    6

    进程与线程的区别

    • 地址空间和其他资源:进程间相互独立,统一进程的各线程间共享。
    • 通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信,但需要通过线程同步和互斥来保证数据的一致性。
    • 调度和切换:线程上下文切换比进程上下文切换要快的多。
    展开全文
  • Python对MySQL同步状态进行监控

    千次阅读 2015-04-02 16:21:15
    使用Python对MySQL数据库服务器是否可访问,及主从同步是否中断进行监控,是一件非常简单的事情。感谢Python给我们带来了如此简单,强大,快捷的开发环境。
  • Python 线程同步 线程优先级

    千次阅读 2017-08-01 11:52:34
    线程同步 如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。 使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire方法和release...
  • python使用ssh监控服务器 python使用跳板机连接mysql
  • Python中线程同步与线程锁

    千次阅读 2019-06-09 21:12:02
    文章目录Python中线程同步与线程锁线程同步threading.Event对象threading.Timer定时器,延迟执行threading.Lock锁可重入锁RLockCondition条件锁,等待通知therading.Semaphore信号量threading.BoundedSemaphore有界...
  • Python实现进程同步和通信

    万次阅读 2017-03-27 17:58:58
    本文介绍了Python中实现进程的同步和通信。使多进程间得以共享资源。 具体介绍了Lock, Semaphore,Queue,Pipe,Manager。
  • python读取接口状态

    2020-05-25 13:26:29
    python读取接口状态 读取下图接口状态 import requests import json # 读取接口信息 def read_palo_interface_Status(pairDate,pairShift,flag): # 实例化session _s1 = requests.Session() # 目标url url = ...
  • python同步,互斥锁,死锁

    千次阅读 2019-04-12 20:20:44
    同步的概念 同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。 "同"字从字面上容易理解为一起动作 其实不是,"同"字应是指协同、协助、互相配合。 如进程、线程同步,可理解为进程或线程A和B一块...
  • python的多线程的同步与其他语言基本相同,主要包含: Lock & RLock :用来确保多线程多共享资源的访问。 Semaphore : 用来确保一定资源多线程访问时的上限,例如资源池。  Event : 是最简单的线程间通信的方式,...
  • 在媒体中心之间同步观看状态的脚本,目前支持Kodi和Plex。 集和电影都受支持。 不支持在电视节目/季节级别同步python的基本知识可以配置/运行它。 跨媒体中心匹配文件是通过文件路径完成的。 如果plex和kodi中的...
  • 帧同步和状态同步(一)

    千次阅读 2017-11-01 09:26:35
    同步什么是帧同步:帧同步常被RTS(即时战略)游戏常采用。在游戏中同步的是玩家的操作指令,操作指令包含当前的帧索引。一般的流程是客户端上传操作到服务器, 服务器收到后并不计算游戏行为, 而是转发到所有...
  • Python多线程—线程同步

    千次阅读 2019-03-25 23:05:17
    当多个线程同时读写同一份共享资源的时候,可能会引起冲突。 这时候,我们需要引入线程“同步”机制,即各位线程之间要有个先来后到,不能一窝蜂挤...Python threading模块提供了Lock/RLock、Condition、queue、Ev...
  • 同步/异步断路器实现 根据Nygard在您的力作《 : 断路器可以防止过度渴望的小猎犬被烧毁。 原理是相同的:检测到过量使用,首先发生故障,然后断开电路。 更抽象地讲,断路器的存在是允许一个子系统(电路)发生...
  • Python中多线程与同步

    千次阅读 2014-03-09 20:50:17
    Python主要通过标准库中的threading包来实现多线程。在当今网络时代,每个服务器都会接收到大量的请求。服务器可以利用多线程...(关于多线程的原理和C实现方法,请参考我之前写的Linux多线程与同步,要了解race condi
  • Python 同步 上锁解锁过程

    千次阅读 2018-11-22 15:17:48
    同步就是协同步调,按预定的先后次序进⾏运⾏ #创建锁  mutex = threading.Lock() #锁定  mutex.acquire([blocking])  #释放 mutex.release() 其中,锁定⽅法acquire可以有⼀个blocking参数。 如果设定...
  • 同步 当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制。同步就是协同步调,按预定的先后次序进行运行。线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。 互斥锁 互斥锁为...
  • Python

    万次阅读 2017-09-23 14:38:03
    Python进阶(一)-初识Python数据元素:列表&元组   毕业论文已完成,下面就是等待盲审结果了。在此期间,已感觉论文无从看起。就学习一下Python吧,听说这是一门很神奇的语言。下面言归正传~    在线文档查询:...
  • python 线程的同步和互斥

    千次阅读 2014-11-10 13:33:20
    当计数器为0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。 实例方法:  [xluren@test thread_communicate]$ cat demo_thread_semaphore.py #!/usr/bin/python import time def ...
  • Python多线程同步---文件读写控制

    万次阅读 2016-01-28 11:37:23
    1、实现文件读写的文件ltz_schedule_times.py#! /usr/bin/env python #coding=utf-8 import osdef ReadTimes(): res = [] if os.path.exists('schedule_times.txt'): fp = open('schedule_times.txt', 'r')
  • python 多线程学习一 (同步与异步)0x00 概念0x01 方法中的同步与异步0x02 图解同步与异步0x03 同步异步与阻塞非阻塞 0x00 概念 定义:同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous ...
  • python的多线程及线程同步方式

    千次阅读 2019-07-17 09:37:23
    线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。 3.2 Semaphore(信号量) 信号量也提供acquire方法和release方法,每当调用acquire方法的时候,如果内部计数器...
  • python多线程 (三) 线程同步

    千次阅读 2019-08-05 19:27:14
    python多线程 (三) 线程同步 如果多个线程共同对某个数据修改,则可能出现数据错误,为了保证数据的正确性,需要对多个线程进行同步。 使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 82,831
精华内容 33,132
关键字:

python状态同步

python 订阅