2014-09-12 15 views
10

Gelecekte koroutinler önlenebilir çünkü? Ya da insanların kritik bölümdeki (IMO'nun teşvik edilmemesi gereken) verimi kullanmalarına izin veriyor mu?Python asyncio.Lock() nedir?

+2

Bu bir kilit, önleme ile ne yapması gerektiğinden emin değil, bir kilit elde etmeye çalıştığınızda, özellikle kilitle tuttuğunuzda size geri verilecek umuduyla kontrol sağlayabilirsiniz. Bir anda bir koroutinin girebileceği kritik bir bölüme sahip olmak içindir. Hepsi dokümanlar içinde. –

+0

Resmi dokümanları dikkatlice okuduğunuzu veya bu soruları anladığınızı sanmıyorum. – user3761759

cevap

18

Aynı nedenden ötürü, dişli bir kodda kilit kullanmanız gerekir: kritik bir bölümü korumak için. asyncio temel olarak tek iş parçacıklı kodda kullanılmak içindir, ancak yine de eşzamanlı yürütme gerçekleşir, bu da bazen eşitleme yapmanız gerektiği anlamına gelir.

@asyncio.coroutine 
def get_stuff(url): 
    if url in cache: 
     return cache[url] 
    stuff = yield from aiohttp.request('GET', url) 
    cache[url] = stuff 
    return stuff 

Şimdi aynı anda potansiyel olarak gerekebilir çalışan birden eş rutinleri var olduğunu varsayalım:

Örneğin, daha sonra bir web sunucusundan bazı verileri getirir ve bir işleve bakalım sonuçlarını önbelleğe

def parse_stuff(): 
    stuff = yield from get_stuff() 
    # do some parsing 

def use_stuff(): 
    stuff = yield from get_stuff() 
    # use stuff to do something interesting 

def do_work(): 
    out = yield from aiohttp.request("www.awebsite.com") 
    # do some work with out 


tasks = [ 
    asyncio.async(parse_stuff()), 
    asyncio.async(use_stuff()), 
    asyncio.async(do_work()), 
] 
loop = asyncio.get_event_loop() 
loop.run_until_complete(asyncio.wait(tasks)) 

Şimdi url veri alınırken yavaş olduğunu iddia: get_stuff dönüş değeri kullanın. Her ikisi de parse_stuff ve use_stuff eşzamanlı olarak çalışırsa, her biri stuff almak için ağ üzerinden geçmenin tam maliyetiyle vurulur. Eğer bir kilit ile yöntemini korumak, bu kaçının:

stuff_lock = asyncio.Lock() 

def get_stuff(url): 
    with (yield from stuff_lock): 
     if url in cache: 
      return cache[url] 
     stuff = yield from aiohttp.request('GET', url) 
     cache[url] = stuff 
     return stuff 

Unutulmaması gereken bir diğer husus ise, bir eşyordam içeride get_stuff, aiohttp arama yapmadan ve stuff_lock başka bekler, etmiyor üçüncü eşyordam iken get_stuff numaralı telefonu aramaya gerek yok, ayrıca Lock üzerinde bulunan coroutine tarafından engellenmeden de çalışıyor olabilir.

Açıkçası, bu örnek biraz da olsa zıttır, ancak umarım, asyncio.Lock'un neden yararlı olabileceği hakkında bir fikir verir; Bu kritik bölümün korunmasını sağlar, diğer koroutinleri engellemeden, 'un bu kritik bölüme erişmesi gerekmez.

+3

Detaylı açıklama için teşekkürler. Bunu özetleyeyim (soruyu anlamayan insanlar için). 1) koroutinler önlenemez - "verim" işlemi tekrar kontrole geri döndürene kadar çalışır. 2) asyncio.Lock(), "verim" olarak adlandırılan kritik bölümleri korumak için kullanılır - aksi halde kilidi kullanmanıza gerek yoktur. Tartışma, tek iş parçacıklı asyncio kullanım modu varsayımı altındadır. – user3761759

+0

Dadaver gibi iyi bir örnek olarak, sözde söylediklerimi tekrarlamak zorundayım - Ben şahsen kritik bölümde “verimden” faydalanma fikrini sevmiyorum. Kulağa ilgisiz geliyor ama söylemeliyim. – user3761759

+0

dano - Bu özel örnekte (aslında akılda tutulduğunu aklınızda tutarak), 'verim' 'i kaldırdıysanız ve bir HTTP isteğini engelleyerek eşdeğer bir performans elde edemez miydiniz? Çünkü kilitleme olduğu gibi, get_stuff() 'ın yalnızca 1 örneği devam edecektir. (B örneğinde olduğu gibi, yalnızca A örneği tamamlandığında başlatılabilir.) –