zoukankan      html  css  js  c++  java
  • 并发编程之上下文管理器(contextlib模块)、协程 -4

    Python中的上下文管理器(contextlib模块)

    上下文管理器的任务是:代码块执行前准备,代码块执行后收拾

    如何使用上下文管理器:

    如何打开一个文件,并写入"hello world"

    filename="my.txt"
    mode="w"
    f=open(filename,mode)
    f.write("hello world")
    f.close()
    View Code

    当发生异常时(如磁盘写满),就没有机会执行第5行。当然,我们可以采用try-finally语句块进行包装:

    writer=open(filename,mode)
    try:
        writer.write("hello world")
    finally:
        writer.close()
    View Code

    当我们进行复杂的操作时,try-finally语句就会变得丑陋,采用with语句重写:

    with open(filename,mode) as writer:
        writer.write("hello world")
    View Code

    as指代了从open()函数返回的内容,并把它赋给了新值。with完成了try-finally的任务。

     自定义上下文管理器 

    with语句的作用类似于try-finally,提供一种上下文机制。要应用with语句的类,其内部必须提供两个内置函数__enter__和__exit__。前者在主体代码执行前执行,后者在主体代码执行后执行。as后面的变量,是在__enter__函数中返回的。

    class echo():
        def output(self):
            print "hello world"
        def __enter__(self):
            print "enter"
            return self  #可以返回任何希望返回的东西
        def __exit__(self,exception_type,value,trackback):
            print "exit"
            if exception_type==ValueError:
                return True
            else:
                return Flase
      
    >>>with echo as e:
        e.output()
         
    输出:
    enter
    hello world
    exit
    View Code

    contextlib模块

    contextlib模块的作用是提供更易用的上下文管理器,它是通过Generator实现的。contextlib中的contextmanager作为装饰器来提供一种针对函数级别的上下文管理机制,常用框架如下:

    from contextlib import contextmanager
    @contextmanager
    def make_context():
        print 'enter'
        try:
            yield "ok"
        except RuntimeError,err:
            print 'error',err
        finally:
            print 'exit'
             
    >>>with make_context() as value:
        print value
         
    输出为:
        enter
        ok
        exit
    View Code

    其中,yield写入try-finally中是为了保证异常安全(能处理异常)as后的变量的值是由yield返回。yield前面的语句可看作代码块执行前操作,yield之后的操作可以看作在__exit__函数中的操作。

    以线程锁为例:

    @contextlib.contextmanager
    def loudLock():
        print 'Locking'
        lock.acquire()
        yield
        print 'Releasing'
        lock.release()
     
    with loudLock():
        print 'Lock is locked: %s' % lock.locked()
        print 'Doing something that needs locking'
     
    #Output:
    #Locking
    #Lock is locked: True
    #Doing something that needs locking
    #Releasing
    View Code

    contextlib.nested:减少嵌套

    with open(filename,mode) as reader,open(filename1,mode1) as writer:
        writer.write(reader.read())
    View Code

    contextlib.closing() 

    file类直接支持上下文管理器API,但有些表示打开句柄的对象并不支持,如urllib.urlopen()返回的对象。还有些遗留类,使用close()方法而不支持上下文管理器API。为了确保关闭句柄,需要使用closing()为它创建一个上下文管理器(调用类的close方法)。

    协程

    协程,又称微线程,纤程。英文名Coroutine。

    优点1: 协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

    优点2: 不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

    因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。

    yield的简单实现

    import time
    import queue
    
    def consumer(name):
        print("--->ready to eat baozi...")
        while True:
            new_baozi = yield
            print("[%s] is eating baozi %s" % (name,new_baozi))
            #time.sleep(1)
    
    def producer():
    
        r = con.__next__()
        r = con2.__next__()
        n = 0
        while 1:
            time.sleep(1)
            print("33[32;1m[producer]33[0m is making baozi %s and %s" %(n,n+1) )
            con.send(n)
            con2.send(n+1)
    
            n +=2
    
    
    if __name__ == '__main__':
        con = consumer("c1")
        con2 = consumer("c2")
        p = producer()
    View Code

    Greenlet

    greenlet是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator

    from greenlet import greenlet
     
     
    def test1():
        print(12)
        gr2.switch()
        print(34)
        gr2.switch()
     
     
    def test2():
        print(56)
        gr1.switch()
        print(78)
     
     
    gr1 = greenlet(test1)
    gr2 = greenlet(test2)
    gr1.switch()
    View Code

    Gevent

    import gevent
    
    import requests,time
    
    
    start=time.time()
    
    def f(url):
        print('GET: %s' % url)
        resp =requests.get(url)
        data = resp.text
        print('%d bytes received from %s.' % (len(data), url))
    
    gevent.joinall([
    
            gevent.spawn(f, 'https://www.python.org/'),
            gevent.spawn(f, 'https://www.yahoo.com/'),
            gevent.spawn(f, 'https://www.baidu.com/'),
            gevent.spawn(f, 'https://www.sina.com.cn/'),
    
    ])
    
    # f('https://www.python.org/')
    #
    # f('https://www.yahoo.com/')
    #
    # f('https://baidu.com/')
    #
    # f('https://www.sina.com.cn/')
    
    print("cost time:",time.time()-start)
    View Code

    参考:http://www.cnblogs.com/yuanchenqi/articles/6248025.html

  • 相关阅读:
    。。。剑指Offer之——用两个栈实现队列。。。
    。。。剑指Offer之——从尾到头打印链表。。。
    。。。剑指Offer之——替换空格。。。
    。。。剑指Offer之——二维数组中的查找。。。
    。。。归并排序。。。
    。。。快速排序。。。
    。。。冒泡排序。。。
    。。。选择排序。。。
    。。。Shell排序。。。
    Activiti学习笔记2 — HelloWorld
  • 原文地址:https://www.cnblogs.com/MR-allen/p/10520104.html
Copyright © 2011-2022 走看看