併發編程之上下文管理器(contextlib模塊)、協程 -4

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

上下文管理器的任務是:代碼塊執行前準備,代碼塊執行後收拾html

如何使用上下文管理器:

如何打開一個文件,並寫入"hello world"python

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__函數中返回的。ide

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__函數中的操做。性能

以線程鎖爲例:ui

@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方法)。url

協程

協程,又稱微線程,纖程。英文名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("\033[32;1m[producer]\033[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

相關文章
相關標籤/搜索