欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python從使用線程到使用async/await的深入講解

 更新時間:2018年09月16日 16:42:24   作者:臨書  
Python在3.5版本中引入了關于協(xié)程的語法糖async和await,所以下面這篇文章主要給大家介紹了關于Python從使用線程到使用async/await的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下

前言

為了簡化并更好地標識異步IO,從Python 3.5開始引入了新的語法async和await,可以讓coroutine的代碼更簡潔易讀。

請注意,async和await是針對coroutine的新語法,要使用新的語法,只需要做兩步簡單的替換:

  • 把@asyncio.rotoutine替換為async;
  • 把yield from替換為await。

async/await 是一種異步變成方法,還有兩種你可能聽過,

     1. 回調

     2. Promise

(寫過 JavaScript 的肯定很熟悉了)

異步意味著任務不會阻塞,比如,如果我要下載一個比較忙的網絡資源,我的程序不需要一直等待下載完成,它可以在等待下載時繼續(xù)做其他事情。這與并行執(zhí)行多個操作不同。以下偽代碼比較容易理解:

# 慢方法
page = get_page_sync('some_page')

# 會阻塞整個程序的運行
print(page)

有兩種方法可以改善上述的情況

(一)首先,讓我們試試使用線程。通過使用線程,我們可以將 get_page_sync 調用放到單獨的線程去執(zhí)行,這樣主線程 就可以繼續(xù)執(zhí)行其他操作。

# 將慢方法放到單獨的線程執(zhí)行
t = threading.thread(
 target = get_page_sync('some_page',args=('some_page',))
)
t.run()

# 在線程運行時執(zhí)行其他操作
do_something_else()

# 等待線程完執(zhí)行成
t.join()

線程有幾個優(yōu)缺點,主要的缺點是:

     1. 必須在改變共享數據前鎖定共享數據

     2. 只能通過傳遞給主線程消息來處理線程內的異常

(二)現在我們試試第二種中的 async/await,Python3.5 開始支持的 async/await 方式,與第一種(線程)之間的主要區(qū)別在于,后者是操作系統(tǒng)內核執(zhí)行上下文切換,而前者中我們自己控制。(上下文切換即,當多個線程正在運行時,內核可能停止當前進程,使其進入休眠狀態(tài),并選擇不同的線程繼續(xù)執(zhí)行。這被稱作搶占式多任務處理【Preemption】)

當我們自己控制時,它被稱作非搶占式或合作型多任務式,因為是我們自己處理上下文切換,所以我們需要一個調度程序,也叫做『事件循環(huán)』。此事件循環(huán)只循環(huán)遍歷等待中的調度,并運行它的所有事件。每當我們產生操作時,當前任務會被添加到隊列中,且第一個任務(優(yōu)先級而非順序)從隊列中彈出并開始執(zhí)行。例如,可以通過以下方式更改上述偽代碼:

async def print_page():
 page = await get_page_sync('some_page')
 print(page)

當我們觸發(fā)上面的語句時,get_page_async 方法將非阻塞的獲取 some_page 還有 yield 句柄,這意味著我們的 print_page 函數將控制時間循環(huán) ,并且時間循環(huán)可以繼續(xù)執(zhí)行其他曹組,知道我們得到返回的響應。

我們先將我們的線程代碼改造成這種語法。我們將使用 asyncio(Python 自帶的時間循環(huán)庫),并使用 aiohttp 包來執(zhí)行異步 http 請求。

我們將會創(chuàng)建一個名為 main 函數,它將成為我們異步代碼的入口。然后我們創(chuàng)建一個時間循環(huán)和一個「未來對象」。這個未來對象是對異步函數的抽象,它存儲了一些基本的屬性,比如它當前的狀態(tài)(就像 Promise 一樣) 。然后我們將告訴我們的時間循環(huán)繼續(xù)運行,知道這個「未來」完成。

loop = asyncio.get_event_loop()
future = asyncio.ensure_future(main())
loop.run_until_complete(future)

在我們的 main 方法中,我們將創(chuàng)建另一個未來任務列表,每個任務負責從某網站下載不同的桐鄉(xiāng)。我們這樣做是因為每次下載都會發(fā)起網絡請求,在網絡請求時,我們可以運行另一端代碼。創(chuàng)建任務列表后,我們可以通過調用等待整個列表執(zhí)行完成 asyncio.gather ,這就是它的實現:

async def main():
 tasks = []
 async with aiohttp.ClientSession() as session:
  for img in img_list:
   task = asyncio.ensure_future(download_img(img, session))
   task.append(task)
 await asyncio.gather(*tasks)

(這段代碼來的有點猛了)

最后一個我們要改的方法就是 download_img 了,我們僅僅需要替換 requests.get 調用為異步:

 i = 1
async def download_img(img, session):
 global i, bar
 
 # 獲取文件后綴
 file_ext = get_extention(img.link)
 # 拼接文件名
 file_name = img.id + file_ext

 resp = await session.get(img.link)
 with open(file_name, 'wb') as f:
  async for chunk in resp.content.iter_chunked(1024):
   f.write(chunk)

 bar.update(i)
 i += 1

要注意的一點是在更新 i 的時候不需要先鎖住它,這是因為我們前面說過,沒有代碼是同時執(zhí)行的,所以永遠不可能出現競態(tài)條件。

因為沒有鎖或者線程的開銷,異步版本可能還會比多線程版本快一些。

這是完整代碼:

#! /usr/bin/env python

import os
import re
import sys

import aiohttp
import asyncio
import async_timeout

import progressbar

from imgurpython import ImgurClient

regex = re.compile(r'\.(\w+)$')
def get_extension(link):
 ext = regex.search(link).group()

 return ext

i = 1
async def download_img(img, session):
 global i, bar

 # get the file extension
 file_ext = get_extension(img.link)
 # create unique name by combining file id with its extension
 file_name = img.id + file_ext

 resp = await session.get(img.link)
 with open(file_name, 'wb') as f:
  async for chunk in resp.content.iter_chunked(1024):
   f.write(chunk)

 bar.update(i)
 i += 1

try:
 album_id = sys.argv[1]
except IndexError:
 raise Exception('Please specify an album id')

client_id = os.getenv('IMGUR_CLIENT_ID')
client_secret = os.getenv('IMGUR_CLIENT_SECRET')
client = ImgurClient(client_id, client_secret)

img_lst = client.get_album_images(album_id)
bar = progressbar.ProgressBar(max_value=len(img_lst))

async def main():
 tasks = []
 async with aiohttp.ClientSession() as session:
  for img in img_lst:
   task = asyncio.ensure_future(download_img(img, session))
   tasks.append(task)

  await asyncio.gather(*tasks)

loop = asyncio.get_event_loop()
future = asyncio.ensure_future(main())
loop.run_until_complete(future)

原文:https://medium.com/@exqu17/python-bits-moving-from-threads-to-async-await-741ec5124cdc

作者:https://medium.com/@exqu17?source=post_header_lockup

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關文章

  • python 處理微信對賬單數據的實例代碼

    python 處理微信對賬單數據的實例代碼

    本文通過實例代碼給大家介紹了python 處理微信對賬單數據,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-07-07
  • Django之模型層多表操作的實現

    Django之模型層多表操作的實現

    這篇文章主要介紹了Django之模型層多表操作的實現,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • python爬蟲 urllib模塊反爬蟲機制UA詳解

    python爬蟲 urllib模塊反爬蟲機制UA詳解

    這篇文章主要介紹了python爬蟲 urllib模塊反爬蟲機制UA詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-08-08
  • python numpy 常用隨機數的產生方法的實現

    python numpy 常用隨機數的產生方法的實現

    這篇文章主要介紹了python numpy 常用隨機數的產生方法的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08
  • Python中的異常處理詳解

    Python中的異常處理詳解

    這篇文章主要介紹了Python中的異常處理詳解,在編寫Python程序時,經常會遇到各種運行時錯誤,這些錯誤會導致程序終止并拋出異常。然而,有時我們希望程序能優(yōu)雅地處理這些錯誤,而不是直接崩潰,這就需要用到異常處理了,需要的朋友可以參考下
    2023-07-07
  • Python3 常用數據標準化方法詳解

    Python3 常用數據標準化方法詳解

    這篇文章主要介紹了Python3 常用數據標準化方法詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • pytorch使用tensorboardX進行l(wèi)oss可視化實例

    pytorch使用tensorboardX進行l(wèi)oss可視化實例

    今天小編就為大家分享一篇pytorch使用tensorboardX進行l(wèi)oss可視化實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • Python基于pyecharts實現關聯(lián)圖繪制

    Python基于pyecharts實現關聯(lián)圖繪制

    這篇文章主要介紹了Python基于pyecharts實現關聯(lián)圖繪制,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • Python上下文管理器Content Manager

    Python上下文管理器Content Manager

    在Python中,我們會經常聽到上下文管理器,那么上下文管理器到底是干什么的,本文就來介紹一下,感興趣的小伙伴們可以參考一下
    2021-06-06
  • python中的netCDF4批量處理NC文件的操作方法

    python中的netCDF4批量處理NC文件的操作方法

    這篇文章主要介紹了python的netCDF4批量處理NC格式文件的操作方法,使用python批量提取所有數據,查看數據屬性,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03

最新評論