## 問(wèn)題
You want to send and receive large arrays of contiguous data across a network connec‐tion, making as few copies of the data as possible.
## 解決方案
The following functions utilize memoryviews to send and receive large arrays:
# zerocopy.py
def send_from(arr, dest):
view = memoryview(arr).cast(‘B')while len(view):
> nsent = dest.send(view)view = view[nsent:]
def recv_into(arr, source):
view = memoryview(arr).cast(‘B')while len(view):
> nrecv = source.recv_into(view)view = view[nrecv:]
To test the program, first create a server and client program connected over a socket.In the server:
>>> from socket import *
>>> s = socket(AF_INET, SOCK_STREAM)
>>> s.bind(('', 25000))
>>> s.listen(1)
>>> c,a = s.accept()
>>>
In the client (in a separate interpreter):
>>> from socket import *
>>> c = socket(AF_INET, SOCK_STREAM)
>>> c.connect(('localhost', 25000))
>>>
Now, the whole idea of this recipe is that you can blast a huge array through the con‐nection. In this case, arrays might be created by the array module or perhaps numpy.For example:# Server>>> import numpy>>> a = numpy.arange(0.0, 50000000.0)>>> send_from(a, c)>>>
# Client>>> import numpy>>> a = numpy.zeros(shape=50000000, dtype=float)>>> a[0:10]array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])>>> recv_into(a, c)>>> a[0:10]array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])>>>
## 討論
In data-intensive distributed computing and parallel programming applications, it’s notuncommon to write programs that need to send/receive large chunks of data. However,to do this, you somehow need to reduce the data down to raw bytes for use with low-level network functions. You may also need to slice the data into chunks, since mostnetwork-related functions aren’t able to send or receive huge blocks of data entirely allat once.One approach is to serialize the data in some way—possibly by converting into a bytestring. However, this usually ends up making a copy of the data. Even if you do thispiecemeal, your code still ends up making a lot of little copies.
This recipe gets around this by playing a sneaky trick with memoryviews. Essentially, amemoryview is an overlay of an existing array. Not only that, memoryviews can be castto different types to allow interpretation of the data in a different manner. This is thepurpose of the following statement:view = memoryview(arr).cast(‘B')
It takes an array arr and casts into a memoryview of unsigned bytes.In this form, the view can be passed to socket-related functions, such as sock.send()or send.recv_into(). Under the covers, those methods are able to work directly withthe memory region. For example, sock.send() sends data directly from memorywithout a copy. send.recv_into() uses the memoryview as the input buffer for thereceive operation.The remaining complication is the fact that the socket functions may only work withpartial data. In general, it will take many different send() and recv_into() calls totransmit the entire array. Not to worry. After each operation, the view is sliced by thenumber of sent or received bytes to produce a new view. The new view is also a memoryoverlay. Thus, no copies are made.One issue here is that the receiver has to know in advance how much data will be sentso that it can either preallocate an array or verify that it can receive the data into anexisting array. If this is a problem, the sender could always arrange to send the size first,followed by the array data.
- Copyright
- 前言
- 第一章:數(shù)據(jù)結(jié)構(gòu)和算法
- 1.1 解壓序列賦值給多個(gè)變量
- 1.2 解壓可迭代對(duì)象賦值給多個(gè)變量
- 1.3 保留最后N個(gè)元素
- 1.4 查找最大或最小的N個(gè)元素
- 1.5 實(shí)現(xiàn)一個(gè)優(yōu)先級(jí)隊(duì)列
- 1.6 字典中的鍵映射多個(gè)值
- 1.7 字典排序
- 1.8 字典的運(yùn)算
- 1.9 查找兩字典的相同點(diǎn)
- 1.10 刪除序列相同元素并保持順序
- 1.11 命名切片
- 1.12 序列中出現(xiàn)次數(shù)最多的元素
- 1.13 通過(guò)某個(gè)關(guān)鍵字排序一個(gè)字典列表
- 1.14 排序不支持原生比較的對(duì)象
- 1.15 通過(guò)某個(gè)字段將記錄分組
- 1.16 過(guò)濾序列元素
- 1.17 從字典中提取子集
- 1.18 映射名稱(chēng)到序列元素
- 1.19 轉(zhuǎn)換并同時(shí)計(jì)算數(shù)據(jù)
- 1.20 合并多個(gè)字典或映射
- 第二章:字符串和文本
- 2.1 使用多個(gè)界定符分割字符串
- 2.2 字符串開(kāi)頭或結(jié)尾匹配
- 2.3 用Shell通配符匹配字符串
- 2.4 字符串匹配和搜索
- 2.5 字符串搜索和替換
- 2.6 字符串忽略大小寫(xiě)的搜索替換
- 2.7 最短匹配模式
- 2.8 多行匹配模式
- 2.9 將Unicode文本標(biāo)準(zhǔn)化
- 2.10 在正則式中使用Unicode
- 2.11 刪除字符串中不需要的字符
- 2.12 審查清理文本字符串
- 2.13 字符串對(duì)齊
- 2.14 合并拼接字符串
- 2.15 字符串中插入變量
- 2.16 以指定列寬格式化字符串
- 2.17 在字符串中處理html和xml
- 2.18 字符串令牌解析
- 2.19 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的遞歸下降分析器
- 2.20 字節(jié)字符串上的字符串操作
- 第三章:數(shù)字日期和時(shí)間
- 3.1 數(shù)字的四舍五入
- 3.2 執(zhí)行精確的浮點(diǎn)數(shù)運(yùn)算
- 3.3 數(shù)字的格式化輸出
- 3.4 二八十六進(jìn)制整數(shù)
- 3.5 字節(jié)到大整數(shù)的打包與解包
- 3.6 復(fù)數(shù)的數(shù)學(xué)運(yùn)算
- 3.7 無(wú)窮大與NaN
- 3.8 分?jǐn)?shù)運(yùn)算
- 3.9 大型數(shù)組運(yùn)算
- 3.10 矩陣與線性代數(shù)運(yùn)算
- 3.11 隨機(jī)選擇
- 3.12 基本的日期與時(shí)間轉(zhuǎn)換
- 3.13 計(jì)算最后一個(gè)周五的日期
- 3.14 計(jì)算當(dāng)前月份的日期范圍
- 3.15 字符串轉(zhuǎn)換為日期
- 3.16 結(jié)合時(shí)區(qū)的日期操作
- 第四章:迭代器與生成器
- 4.1 手動(dòng)遍歷迭代器
- 4.2 代理迭代
- 4.3 使用生成器創(chuàng)建新的迭代模式
- 4.4 實(shí)現(xiàn)迭代器協(xié)議
- 4.5 反向迭代
- 4.6 帶有外部狀態(tài)的生成器函數(shù)
- 4.7 迭代器切片
- 4.8 跳過(guò)可迭代對(duì)象的開(kāi)始部分
- 4.9 排列組合的迭代
- 4.10 序列上索引值迭代
- 4.11 同時(shí)迭代多個(gè)序列
- 4.12 不同集合上元素的迭代
- 4.13 創(chuàng)建數(shù)據(jù)處理管道
- 4.14 展開(kāi)嵌套的序列
- 4.15 順序迭代合并后的排序迭代對(duì)象
- 4.16 迭代器代替while無(wú)限循環(huán)
- 第五章:文件與IO
- 5.1 讀寫(xiě)文本數(shù)據(jù)
- 5.2 打印輸出至文件中
- 5.3 使用其他分隔符或行終止符打印
- 5.4 讀寫(xiě)字節(jié)數(shù)據(jù)
- 5.5 文件不存在才能寫(xiě)入
- 5.6 字符串的I/O操作
- 5.7 讀寫(xiě)壓縮文件
- 5.8 固定大小記錄的文件迭代
- 5.9 讀取二進(jìn)制數(shù)據(jù)到可變緩沖區(qū)中
- 5.10 內(nèi)存映射的二進(jìn)制文件
- 5.11 文件路徑名的操作
- 5.12 測(cè)試文件是否存在
- 5.13 獲取文件夾中的文件列表
- 5.14 忽略文件名編碼
- 5.15 打印不合法的文件名
- 5.16 增加或改變已打開(kāi)文件的編碼
- 5.17 將字節(jié)寫(xiě)入文本文件
- 5.18 將文件描述符包裝成文件對(duì)象
- 5.19 創(chuàng)建臨時(shí)文件和文件夾
- 5.20 與串行端口的數(shù)據(jù)通信
- 5.21 序列化Python對(duì)象
- 第六章:數(shù)據(jù)編碼和處理
- 6.1 讀寫(xiě)CSV數(shù)據(jù)
- 6.2 讀寫(xiě)JSON數(shù)據(jù)
- 6.3 解析簡(jiǎn)單的XML數(shù)據(jù)
- 6.4 增量式解析大型XML文件
- 6.5 將字典轉(zhuǎn)換為XML
- 6.6 解析和修改XML
- 6.7 利用命名空間解析XML文檔
- 6.8 與關(guān)系型數(shù)據(jù)庫(kù)的交互
- 6.9 編碼和解碼十六進(jìn)制數(shù)
- 6.10 編碼解碼Base64數(shù)據(jù)
- 6.11 讀寫(xiě)二進(jìn)制數(shù)組數(shù)據(jù)
- 6.12 讀取嵌套和可變長(zhǎng)二進(jìn)制數(shù)據(jù)
- 6.13 數(shù)據(jù)的累加與統(tǒng)計(jì)操作
- 第七章:函數(shù)
- 7.1 可接受任意數(shù)量參數(shù)的函數(shù)
- 7.2 只接受關(guān)鍵字參數(shù)的函數(shù)
- 7.3 給函數(shù)參數(shù)增加元信息
- 7.4 返回多個(gè)值的函數(shù)
- 7.5 定義有默認(rèn)參數(shù)的函數(shù)
- 7.6 定義匿名或內(nèi)聯(lián)函數(shù)
- 7.7 匿名函數(shù)捕獲變量值
- 7.8 減少可調(diào)用對(duì)象的參數(shù)個(gè)數(shù)
- 7.9 將單方法的類(lèi)轉(zhuǎn)換為函數(shù)
- 7.10 帶額外狀態(tài)信息的回調(diào)函數(shù)
- 7.11 內(nèi)聯(lián)回調(diào)函數(shù)
- 7.12 訪問(wèn)閉包中定義的變量
- 第八章:類(lèi)與對(duì)象
- 8.1 改變對(duì)象的字符串顯示
- 8.2 自定義字符串的格式化
- 8.3 讓對(duì)象支持上下文管理協(xié)議
- 8.4 創(chuàng)建大量對(duì)象時(shí)節(jié)省內(nèi)存方法
- 8.5 在類(lèi)中封裝屬性名
- 8.6 創(chuàng)建可管理的屬性
- 8.7 調(diào)用父類(lèi)方法
- 8.8 子類(lèi)中擴(kuò)展property
- 8.9 創(chuàng)建新的類(lèi)或?qū)嵗龑傩?/a>
- 8.10 使用延遲計(jì)算屬性
- 8.11 簡(jiǎn)化數(shù)據(jù)結(jié)構(gòu)的初始化
- 8.12 定義接口或者抽象基類(lèi)
- 8.13 實(shí)現(xiàn)數(shù)據(jù)模型的類(lèi)型約束
- 8.14 實(shí)現(xiàn)自定義容器
- 8.15 屬性的代理訪問(wèn)
- 8.16 在類(lèi)中定義多個(gè)構(gòu)造器
- 8.17 創(chuàng)建不調(diào)用init方法的實(shí)例
- 8.18 利用Mixins擴(kuò)展類(lèi)功能
- 8.19 實(shí)現(xiàn)狀態(tài)對(duì)象或者狀態(tài)機(jī)
- 8.20 通過(guò)字符串調(diào)用對(duì)象方法
- 8.21 實(shí)現(xiàn)訪問(wèn)者模式
- 8.22 不用遞歸實(shí)現(xiàn)訪問(wèn)者模式
- 8.23 循環(huán)引用數(shù)據(jù)結(jié)構(gòu)的內(nèi)存管理
- 8.24 讓類(lèi)支持比較操作
- 8.25 創(chuàng)建緩存實(shí)例
- 第九章:元編程
- 9.1 在函數(shù)上添加包裝器
- 9.2 創(chuàng)建裝飾器時(shí)保留函數(shù)元信息
- 9.3 解除一個(gè)裝飾器
- 9.4 定義一個(gè)帶參數(shù)的裝飾器
- 9.5 可自定義屬性的裝飾器
- 9.6 帶可選參數(shù)的裝飾器
- 9.7 利用裝飾器強(qiáng)制函數(shù)上的類(lèi)型檢查
- 9.8 將裝飾器定義為類(lèi)的一部分
- 9.9 將裝飾器定義為類(lèi)
- 9.10 為類(lèi)和靜態(tài)方法提供裝飾器
- 9.11 裝飾器為被包裝函數(shù)增加參數(shù)
- 9.12 使用裝飾器擴(kuò)充類(lèi)的功能
- 9.13 使用元類(lèi)控制實(shí)例的創(chuàng)建
- 9.14 捕獲類(lèi)的屬性定義順序
- 9.15 定義有可選參數(shù)的元類(lèi)
- 9.16 *args和**kwargs的強(qiáng)制參數(shù)簽名
- 9.17 在類(lèi)上強(qiáng)制使用編程規(guī)約
- 9.18 以編程方式定義類(lèi)
- 9.19 在定義的時(shí)候初始化類(lèi)的成員
- 9.20 利用函數(shù)注解實(shí)現(xiàn)方法重載
- 9.21 避免重復(fù)的屬性方法
- 9.22 定義上下文管理器的簡(jiǎn)單方法
- 9.23 在局部變量域中執(zhí)行代碼
- 9.24 解析與分析Python源碼
- 9.25 拆解Python字節(jié)碼
- 第十章:模塊與包
- 10.1 構(gòu)建一個(gè)模塊的層級(jí)包
- 10.2 控制模塊被全部導(dǎo)入的內(nèi)容
- 10.3 使用相對(duì)路徑名導(dǎo)入包中子模塊
- 10.4 將模塊分割成多個(gè)文件
- 10.5 利用命名空間導(dǎo)入目錄分散的代碼
- 10.6 重新加載模塊
- 10.7 運(yùn)行目錄或壓縮文件
- 10.8 讀取位于包中的數(shù)據(jù)文件
- 10.9 將文件夾加入到sys.path
- 10.10 通過(guò)字符串名導(dǎo)入模塊
- 10.11 通過(guò)導(dǎo)入鉤子遠(yuǎn)程加載模塊
- 10.12 導(dǎo)入模塊的同時(shí)修改模塊
- 10.13 安裝私有的包
- 10.14 創(chuàng)建新的Python環(huán)境
- 10.15 分發(fā)包
- 第十一章:網(wǎng)絡(luò)與Web編程
- 11.1 作為客戶端與HTTP服務(wù)交互
- 11.2 創(chuàng)建TCP服務(wù)器
- 11.3 創(chuàng)建UDP服務(wù)器
- 11.4 通過(guò)CIDR地址生成對(duì)應(yīng)的IP地址集
- 11.5 生成一個(gè)簡(jiǎn)單的REST接口
- 11.6 通過(guò)XML-RPC實(shí)現(xiàn)簡(jiǎn)單的遠(yuǎn)程調(diào)用
- 11.7 在不同的Python解釋器之間交互
- 11.8 實(shí)現(xiàn)遠(yuǎn)程方法調(diào)用
- 11.9 簡(jiǎn)單的客戶端認(rèn)證
- 11.10 在網(wǎng)絡(luò)服務(wù)中加入SSL
- 11.11 進(jìn)程間傳遞Socket文件描述符
- 11.12 理解事件驅(qū)動(dòng)的IO
- 11.13 發(fā)送與接收大型數(shù)組
- 第十二章:并發(fā)編程
- 12.1 啟動(dòng)與停止線程
- 12.2 判斷線程是否已經(jīng)啟動(dòng)
- 12.3 線程間的通信
- 12.4 給關(guān)鍵部分加鎖
- 12.5 防止死鎖的加鎖機(jī)制
- 12.6 保存線程的狀態(tài)信息
- 12.7 創(chuàng)建一個(gè)線程池
- 12.8 簡(jiǎn)單的并行編程
- 12.9 Python的全局鎖問(wèn)題
- 12.10 定義一個(gè)Actor任務(wù)
- 12.11 實(shí)現(xiàn)消息發(fā)布/訂閱模型
- 12.12 使用生成器代替線程
- 12.13 多個(gè)線程隊(duì)列輪詢(xún)
- 12.14 在Unix系統(tǒng)上面啟動(dòng)守護(hù)進(jìn)程
- 第十三章:腳本編程與系統(tǒng)管理
- 13.1 通過(guò)重定向/管道/文件接受輸入
- 13.2 終止程序并給出錯(cuò)誤信息
- 13.3 解析命令行選項(xiàng)
- 13.4 運(yùn)行時(shí)彈出密碼輸入提示
- 13.5 獲取終端的大小
- 13.6 執(zhí)行外部命令并獲取它的輸出
- 13.7 復(fù)制或者移動(dòng)文件和目錄
- 13.8 創(chuàng)建和解壓壓縮文件
- 13.9 通過(guò)文件名查找文件
- 13.10 讀取配置文件
- 13.11 給簡(jiǎn)單腳本增加日志功能
- 13.12 給內(nèi)庫(kù)增加日志功能
- 13.13 記錄程序執(zhí)行的時(shí)間
- 13.14 限制內(nèi)存和CPU的使用量
- 13.15 啟動(dòng)一個(gè)WEB瀏覽器
- 第十四章:測(cè)試調(diào)試和異常
- 14.1 測(cè)試輸出到標(biāo)準(zhǔn)輸出上
- 14.2 在單元測(cè)試中給對(duì)象打補(bǔ)丁
- 14.3 在單元測(cè)試中測(cè)試異常情況
- 14.4 將測(cè)試輸出用日志記錄到文件中
- 14.5 忽略或者期望測(cè)試失敗
- 14.6 處理多個(gè)異常
- 14.7 捕獲所有異常
- 14.8 創(chuàng)建自定義異常
- 14.9 捕獲異常后拋出另外的異常
- 14.10 重新拋出最后的異常
- 14.11 輸出警告信息
- 14.12 調(diào)試基本的程序崩潰錯(cuò)誤
- 14.13 給你的程序做基準(zhǔn)測(cè)試
- 14.14 讓你的程序跑的更快
- 第十五章:C語(yǔ)言擴(kuò)展
- 15.1 使用ctypes訪問(wèn)C代碼
- 15.2 簡(jiǎn)單的C擴(kuò)展模塊
- 15.3 一個(gè)操作數(shù)組的擴(kuò)展函數(shù)
- 15.4 在C擴(kuò)展模塊中操作隱形指針
- 15.5 從擴(kuò)張模塊中定義和導(dǎo)出C的API
- 15.6 從C語(yǔ)言中調(diào)用Python代碼
- 15.7 從C擴(kuò)展中釋放全局鎖
- 15.8 C和Python中的線程混用
- 15.9 用WSIG包裝C代碼
- 15.10 用Cython包裝C代碼
- 15.11 用Cython寫(xiě)高性能的數(shù)組操作
- 15.12 將函數(shù)指針轉(zhuǎn)換為可調(diào)用對(duì)象
- 15.13 傳遞NULL結(jié)尾的字符串給C函數(shù)庫(kù)
- 15.14 傳遞Unicode字符串給C函數(shù)庫(kù)
- 15.15 C字符串轉(zhuǎn)換為Python字符串
- 15.16 不確定編碼格式的C字符串
- 15.17 傳遞文件名給C擴(kuò)展
- 15.18 傳遞已打開(kāi)的文件給C擴(kuò)展
- 15.19 從C語(yǔ)言中讀取類(lèi)文件對(duì)象
- 15.20 處理C語(yǔ)言中的可迭代對(duì)象
- 15.21 診斷分析代碼錯(cuò)誤
- 附錄A
- 關(guān)于譯者
- Roadmap
