Python中使用asyncio 封裝檔案讀寫_python

來源:互聯網
上載者:User

前言

和網路 IO 一樣,檔案讀寫同樣是一個費事的操作。

預設情況下,Python 使用的是系統的阻塞讀寫。這意味著在 asyncio 中如果調用了

f = file('xx')f.read()

會阻塞事件迴圈。

本篇簡述如何用 asyncio.Future 對象來封裝檔案的非同步讀寫。

代碼在 GitHub。目前僅支援 Linux。

阻塞和非阻塞

首先需要將檔案的讀寫改為非阻塞的形式。在非阻塞情況下,每次調用 read 都會立即返回,如果傳回值為空白,則意味著檔案操作還未完成,反之則是讀取的檔案內容。

阻塞和非阻塞的切換與作業系統有關,所以本篇暫時唯寫了 Linux 版本。如果有過 Unix 系統編程經驗,會發現 Python 的操作是類似的。

flag = fcntl.fcntl(self.fd, fcntl.F_GETFL) if fcntl.fcntl(self.fd, fcntl.F_SETFL, flag | os.O_NONBLOCK) != 0:   raise OSError() 

Future 對象

Future 對象類似 Javascript 中的 Promise 對象。它是一個預留位置,其值會在將來被計算出來。我們可以使用

result = await future

在 future 得到值之後返回。而使用

future.set_result(xxx)

就可以設定 future 的值,也意味著 future 可以被返回了。await 操作符會自動調用 future.result() 來得到值。

loop.call_soon

通過 loop.call_soon 方法可以將一個函數插入到事件迴圈中。

至此,我們的非同步檔案讀寫思路也就出來了。通過 loop.call_soon 調用非阻塞讀寫檔案的函數。若一次檔案讀寫沒有完成,則計算剩餘所學讀寫的位元組數,並再次插入事件迴圈直至讀寫完畢。

可以發現其就是把傳統 Unix 編程裡,非阻塞檔案讀寫的 while 迴圈換成了 asyncio 的事件迴圈。

下面是這一過程的示意代碼。

def read_step(self, future, n, total):  res = self.fd.read(n)  if res is None:    self.loop.call_soon(self.read_step, future, n, total)    return  if not res: # EOF    future.set_result(bytes(self.rbuffer))    return  self.rbuffer.extend(res)  self.loop.call_soon(self.read_step, future, self.BLOCK_SIZE, total)def read(self, n=-1):  future = asyncio.Future(loop=self.loop)  self.rbuffer.clear()  self.loop.call_soon(self.read_step, future, min(self.BLOCK_SIZE, n), n)  return future

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.