91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python中怎么實現同步和異步

發布時間:2021-07-05 17:23:03 來源:億速云 閱讀:688 作者:Leah 欄目:編程語言

Python中怎么實現同步和異步,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

一、同步與異步

#同步編程(同一時間只能做一件事,做完了才能做下一件事情)  <-a_url-><-b_url-><-c_url->  #異步編程 (可以近似的理解成同一時間有多個事情在做,但有先后)  <-a_url->    <-b_url->      <-c_url->        <-d_url->          <-e_url->            <-f_url->              <-g_url->                <-h_url->                  <--i_url-->                    <--j_url-->

模板

import asyncio  #函數名:做現在的任務時不等待,能繼續做別的任務。  async def donow_meantime_dontwait(url):      response = await requests.get(url)  #函數名:快速高效的做任務  async def fast_do_your_thing():      await asyncio.wait([donow_meantime_dontwait(url) for url in urls])  #下面兩行都是套路,記住就好  loop = asyncio.get_event_loop()  loop.run_until_complete(fast_do_your_thing())

tips:

await表達式中的對象必須是awaitable

requests不支持非阻塞

aiohttp是用于異步請求的庫

代碼

import asyncio import requests import time import aiohttp urls = ['https://book.douban.com/tag/小說','https://book.douban.com/tag/科幻',         'https://book.douban.com/tag/漫畫','https://book.douban.com/tag/奇幻',         'https://book.douban.com/tag/歷史','https://book.douban.com/tag/經濟學'] async def requests_meantime_dont_wait(url):     print(url)     async with aiohttp.ClientSession() as session:         async with session.get(url) as resp:             print(resp.status)             print("{url} 得到響應".format(url=url)) async def fast_requsts(urls):     start = time.time()     await asyncio.wait([requests_meantime_dont_wait(url) for url in urls])     end = time.time()     print("Complete in {} seconds".format(end - start)) loop = asyncio.get_event_loop() loop.run_until_complete(fast_requsts(urls))

gevent簡介

gevent是一個python的并發庫,它為各種并發和網絡相關的任務提供了整潔的API。

gevent中用到的主要模式是greenlet,它是以C擴展模塊形式接入Python的輕量級協程。 greenlet全部運行在主程序操作系統進程的內部,但它們被協作式地調度。

猴子補丁

requests庫是阻塞式的,為了將requests同步更改為異步。只有將requests庫阻塞式更改為非阻塞,異步操作才能實現。

而gevent庫中的猴子補丁(monkey patch),gevent能夠修改標準庫里面大部分的阻塞式系統調用。這樣在不改變原有代碼的情況下,將應用的阻塞式方法,變成協程式的(異步)。

代碼

from gevent import monkey  import gevent  import requests  import time   monkey.patch_all()  def req(url):      print(url)      resp = requests.get(url)      print(resp.status_code,url)   def synchronous_times(urls):      """同步請求運行時間"""      start = time.time()      for url in urls:          req(url)      end = time.time()      print('同步執行時間 {} s'.format(end-start))   def asynchronous_times(urls):      """異步請求運行時間"""      start = time.time()      gevent.joinall([gevent.spawn(req,url) for url in urls])      end = time.time()      print('異步執行時間 {} s'.format(end - start))   urls = ['https://book.douban.com/tag/小說','https://book.douban.com/tag/科幻',          'https://book.douban.com/tag/漫畫','https://book.douban.com/tag/奇幻',          'https://book.douban.com/tag/歷史','https://book.douban.com/tag/經濟學']   synchronous_times(urls)  asynchronous_times(urls)

gevent:異步理論與實戰

Python中怎么實現同步和異步

gevent庫中使用的最核心的是Greenlet-一種用C寫的輕量級python模塊。在任意時間,系統只能允許一個Greenlet處于運行狀態

一個greenlet遇到IO操作時,比如訪問網絡,就自動切換到其他的greenlet,等到IO操作完成,再在適當的時候切換回來繼續執行。由于IO操作非常耗時,經常使程序處于等待狀態,有了gevent為我們自動切換協程,就保證總有greenlet在運行,而不是等待IO。

串行和異步

高并發的核心是讓一個大的任務分成一批子任務,并且子任務會被被系統高效率的調度,實現同步或者異步。在兩個子任務之間切換,也就是經常說到的上下文切換。

同步就是讓子任務串行,而異步有點影分身之術,但在任意時間點,真身只有一個,子任務并不是真正的并行,而是充分利用了碎片化的時間,讓程序不要浪費在等待上。這就是異步,效率杠桿的。

gevent中的上下文切換是通過yield實現。在這個例子中,我們會有兩個子任務,互相利用對方等待的時間做自己的事情。這里我們使用gevent.sleep(0)代表程序會在這里停0秒。

import gevent  def foo():      print('Running in foo')      gevent.sleep(0)      print('Explicit context switch to foo again')   def bar():      print('Explicit context to bar')      gevent.sleep(0)      print('Implicit context switch back to bar')   gevent.joinall([      gevent.spawn(foo),      gevent.spawn(bar)      ])

運行的順序:

Running in foo  Explicit context to bar  Explicit context switch to foo again  Implicit context switch back to bar

同步異步的順序問題

同步運行就是串行,123456...,但是異步的順序是隨機的任意的(根據子任務消耗的時間而定)

代碼

import gevent  import random  def task(pid):      """      Some non-deterministic task      """      gevent.sleep(random.randint(0,2)*0.001)      print('Task %s done' % pid)    #同步(結果更像串行)  def synchronous():      for i in range(1,10):          task(i)    #異步(結果更像亂步)  def asynchronous():      threads = [gevent.spawn(task, i) for i in range(10)]      gevent.joinall(threads)    print('Synchronous同步:')  synchronous()    print('Asynchronous異步:')  asynchronous()

輸出

Synchronous同步:

Task 1 done  Task 2 done  Task 3 done Task 4 done  Task 5 done  Task 6 done  Task 7 done  Task 8 done  Task 9 done

Asynchronous異步:

Task 1 done  Task 5 done  Task 6 done  Task 2 done  Task 4 done  Task 7 done  Task 8 done  Task 9 done  Task 0 done  Task 3 done

同步案例中所有的任務都是按照順序執行,這導致主程序是阻塞式的(阻塞會暫停主程序的執行)。

gevent.spawn會對傳入的任務(子任務集合)進行進行調度,gevent.joinall方法會阻塞當前程序,除非所有的greenlet都執行完畢,程序才會結束。

實戰

實現gevent到底怎么用,把異步訪問得到的數據提取出來。

在有道詞典搜索框輸入“hello”按回車。觀察數據請求情況 觀察有道的url構建。

分析url規律

#url構建只需要傳入word即可  url = "http://dict.youdao.com/w/eng/{}/".format(word)

解析網頁數據

def fetch_word_info(word):      url = "http://dict.youdao.com/w/eng/{}/".format(word)       resp = requests.get(url,headers=headers)      doc = pq(resp.text)      pros = ''      for pro in doc.items('.baav .pronounce'):          pros+=pro.text()       description = ''      for li in doc.items('#phrsListTab .trans-container ul li'):          description +=li.text()       return {'word':word,'音標':pros,'注釋':description}

因為requests庫在任何時候只允許有一個訪問結束完全結束后,才能進行下一次訪問。無法通過正規途徑拓展成異步,因此這里使用了monkey補丁

同步代碼

import requests  from pyquery import PyQuery as pq  import gevent  import time  import gevent.monkey  gevent.monkey.patch_all()  words = ['good','bad','cool',           'hot','nice','better',           'head','up','down',           'right','left','east']   def synchronous():      start = time.time()      print('同步開始了')      for word in words:          print(fetch_word_info(word))      end = time.time()      print("同步運行時間: %s 秒" % str(end - start))   #執行同步  synchronous()

異步代碼

import requests  from pyquery import PyQuery as pq  import gevent  import time  import gevent.monkey  gevent.monkey.patch_all()   words = ['good','bad','cool',           'hot','nice','better',           'head','up','down',           'right','left','east']   def asynchronous():      start = time.time()      print('異步開始了')      events = [gevent.spawn(fetch_word_info,word) for word in words]      wordinfos = gevent.joinall(events)      for wordinfo in wordinfos:          #獲取到數據get方法          print(wordinfo.get())      end = time.time()      print("異步運行時間: %s 秒"%str(end-start))   #執行異步  asynchronous()

我們可以對待爬網站實時異步訪問,速度會大大提高。我們現在是爬取12個詞語的信息,也就是說一瞬間我們對網站訪問了12次,這還沒啥問題,假如爬10000+個詞語,使用gevent的話,那幾秒鐘之內就給網站一股腦的發請求,說不定網站就把爬蟲封了。

解決辦法

將列表等分為若干個子列表,分批爬取。舉例我們有一個數字列表(0-19),要均勻的等分為4份,也就是子列表有5個數。下面是我在stackoverflow查找到的列表等分方案:

方法1

seqence = list(range(20))  size = 5 #子列表長度  output = [seqence[i:i+size] for i in range(0, len(seqence), size)]  print(output)

方法2

chunks = lambda seq, size: [seq[i: i+size] for i in range(0, len(seq), size)]  print(chunks(seq, 5))

方法3

def chunks(seq,size):      for i in range(0,len(seq), size):          yield seq[i:i+size]  prinT(chunks(seq,5))      for  x  in chunks(req,5):           print(x)

數據量不大的情況下,選哪一種方法都可以。如果特別大,建議使用方法3.

動手實現

import requests  from pyquery import PyQuery as pq  import gevent  import time  import gevent.monkey  gevent.monkey.patch_all() words = ['good','bad','cool',           'hot','nice','better',           'head','up','down',           'right','left','east']   def fetch_word_info(word):       url = "http://dict.youdao.com/w/eng/{}/".format(word)       resp = requests.get(url,headers=headers)      doc = pq(resp.text)       pros = ''      for pro in doc.items('.baav .pronounce'):          pros+=pro.text()       description = ''      for li in doc.items('#phrsListTab .trans-container ul li'):          description +=li.text()       return {'word':word,'音標':pros,'注釋':description}    def asynchronous(words):      start = time.time()      print('異步開始了')        chunks = lambda seq, size: [seq[i: i + size] for i in range(0, len(seq), size)]       for subwords in chunks(words,3):          events = [gevent.spawn(fetch_word_info, word) for word in subwords]           wordinfos = gevent.joinall(events)          for wordinfo in wordinfos:              # 獲取到數據get方法              print(wordinfo.get())          time.sleep(1)           end = time.time()      print("異步運行時間: %s 秒" % str(end - start))   asynchronous(words)

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

龙川县| 繁昌县| 德清县| 双牌县| 区。| 清涧县| 峨眉山市| 获嘉县| 桦川县| 黎城县| 延川县| 南昌县| 阿拉尔市| 化州市| 永德县| 舟山市| 天门市| 漾濞| 庄河市| 响水县| 禹城市| 蒲江县| 陕西省| 玛曲县| 咸阳市| 黑水县| 永兴县| 宿迁市| 凉山| 尉犁县| 那曲县| 汝南县| 时尚| 新平| 乐陵市| 河西区| 湛江市| 龙江县| 马公市| 光泽县| 特克斯县|