2011-11-16 29 views
6

在Python中將二進制數據字符串轉換爲數值的最快方法是什麼?Python中的快速二進制數據轉換

我使用的是struct.unpack_from(),但是達到了性能極限。

上下文:傳入流是混合的二進制和ASCII數據。 ASCII數據轉換在C中通過ctypes完成。通過ctypes實現在C中解壓縮產生了與解壓縮類似的性能。我的猜測是通話開銷太多了。我希望找到一種本地的類似C的強制方法(無論是非Pythonic)。最有可能所有這些代碼將需要移動到C.

該流是在網絡字節順序(big-endian),並且該機器是little-endian。轉換例是:

import struct 
network_stream = struct.pack('>I', 0x12345678) 
(converted_int,) = struct.unpack_from('>I', network_stream, 0) 

我不太關心處理流格式,不是二進制轉換一般情況下,如果有甚至unpack的替代品。例如,socket.ntohl()需要一個int,而int()不會轉換二進制數據字符串。

感謝您的建議!

+0

您究竟是什麼開箱的?它只是一個統一的數值數組嗎? –

+0

不幸的是,它是一個單身人士的混合流,其中的內容由一個標題表示。大部分轉換是針對4B整數和浮點數的。 – CNK

+1

測試用例在這裏不錯 – Triptych

回答

2

速度問題可能不在struct.unpack_from()本身的實現中,而是在Python所需的其他任務中執行—字典查找,創建對象,調用函數和其他任務。您可以通過消除這些字典查找一個通過導入unpack_from,而不是直接從struct模塊得到它每一次有史以來加快速度非常輕微:

$ python -m timeit -s "import struct; network_stream = struct.pack('>I', 0x12345678)" "(converted_int,) = struct.unpack_from('>I', network_stream, 0)" 
1000000 loops, best of 3: 0.277 usec per loop 

$ python -m timeit -s "import struct; from struct import unpack_from; network_stream = struct.pack('>I', 0x12345678)" "(converted_int,) = unpack_from('>I', network_stream, 0)" 
1000000 loops, best of 3: 0.258 usec per loop 

但是,如果需要有大量的分析邏輯是需要一次解包一個數字,並且可以防止整批數據解包,無論您打電話給您做什麼都沒有關係。您可能需要以較少開銷的語言來完成整個內部循環,例如C.

+0

有趣的想法。我實際上使用'從結構導入*'。將其轉換爲模仿您的示例,並在約220M的調用中發現5%的性能差異。永遠不會有這樣的預期。謝謝! – CNK

2

根據我的經驗,你是正確的代碼將需要被移動到C.當你發現爲二進制轉換的各種工具的性能(structctypes例如)具有大致相同的性能。

Cython是爲Python生成C擴展的最簡單方法。

另一個簡單的方法是放棄CPython,完全支持pypy,它可以使用跟蹤JIT生成高質量的低級代碼。

更具挑戰性但更直接的方法是編寫一個普通的C擴展。這並不好玩,但並不困難。

+0

您估計哪種方法具有最低的通話開銷? C擴展會比使用ctypes更高效嗎? – CNK

+1

C擴展可以永遠贏得勝利,因爲它有機會一次執行多次轉換(每次返回列表中或迭代器中的數字)。 * ctypes *方法每次轉換的粒度爲一次調用。另外,你不需要所有的數據,所以C擴展可以跳過不需要的值,保存許多convert/allocate/incref/compare/jump/decref週期。 –