2011-11-16 50 views
6

Phương pháp nhanh nhất để chuyển đổi chuỗi dữ liệu nhị phân thành giá trị số bằng Python là gì?chuyển đổi dữ liệu nhị phân nhanh trong Python

Tôi đang sử dụng struct.unpack_from() nhưng đang đạt đến giới hạn hiệu suất.

Bối cảnh: luồng đến là dữ liệu nhị phân và ASCII hỗn hợp. Việc chuyển đổi dữ liệu ASCII được thực hiện bằng C mặc dù ctypes. Việc triển khai giải nén trong C thông qua các ctypes mang lại hiệu suất tương tự để giải nén. Tôi đoán là chi phí cuộc gọi quá nhiều yếu tố. Tôi đã hy vọng tìm thấy một phương pháp cưỡng chế C giống như bản địa (tuy nhiên không phải Pythonic). Rất có thể tất cả các mã này sẽ cần phải di chuyển đến C.

Luồng theo thứ tự byte mạng (lớn cuối) và máy nhỏ gọn. Một chuyển đổi ví dụ sẽ là:

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

tôi ít quan tâm đến việc xử lý các định dạng stream, so với các trường hợp chung của chuyển đổi nhị phân, và nếu có, ngay cả một thay thế cho unpack. Ví dụ: socket.ntohl() yêu cầu một int và int() sẽ không chuyển đổi chuỗi dữ liệu nhị phân.

Cảm ơn đề xuất của bạn!

+0

Chính xác bạn đang giải nén những gì? Nó chỉ đơn giản là một mảng đồng nhất của các giá trị số? –

+0

Thật không may nó là một dòng hỗn hợp của các đơn, nơi mà nội dung được chỉ ra bởi một tiêu đề. Hầu hết các chuyển đổi là cho 4B số nguyên và phao nổi. – CNK

+1

trường hợp thử nghiệm sẽ được tốt đẹp ở đây – Triptych

Trả lời

2

Vấn đề về tốc độ có thể không có trong việc thực hiện struct.unpack_from(), nhưng trong mọi thứ khác, Python cần làm — tra cứu từ điển, tạo đối tượng, chức năng gọi và các tác vụ khác. Bạn có thể điều tốc độ lên bao giờ nên hơi bằng cách loại bỏ một trong các tra cứu từ điển bằng cách nhập unpack_from trực tiếp chứ không phải là nhận được nó từ các mô-đun struct mỗi lần:

$ 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 

Tuy nhiên, nếu cần phải có rất nhiều phân tích logic đòi hỏi phải giải nén một số tại một thời điểm và sẽ giúp bạn không giải nén toàn bộ mảng dữ liệu hàng loạt, điều đó không quan trọng bạn gọi để làm gì cho bạn. Có thể bạn sẽ cần phải thực hiện toàn bộ vòng lặp bên trong này bằng một ngôn ngữ có ít chi phí hơn, chẳng hạn như C.

+0

Tư tưởng thú vị. Tôi thực sự đã sử dụng 'từ struct import *'. Chuyển đổi điều này để bắt chước ví dụ của bạn và cũng tìm thấy sự khác biệt hiệu suất 5% trong khoảng 220 triệu cuộc gọi. Sẽ không bao giờ mong đợi điều đó. Cảm ơn! – CNK

2

Dựa trên kinh nghiệm của tôi, bạn là chính xác rằng mã sẽ cần phải được chuyển đến C. Như bạn đã khám phá ra hiệu suất cho các công cụ khác nhau để chuyển đổi nhị phân (structctypes ví dụ) có hiệu suất xấp xỉ tương tự .

Cython là cách dễ nhất để tạo tiện ích mở rộng C cho Python.

Một cách tiếp cận dễ dàng khác là từ bỏ CPython hoàn toàn có lợi cho pypy có thể tạo mã chất lượng cao, cấp thấp bằng cách sử dụng dấu vết JIT của nó.

Một cách tiếp cận khó khăn hơn nhưng trực tiếp hơn là viết phần mở rộng C đơn giản. Đây không phải là niềm vui nhưng nó không phải là khó khăn.

+0

Bạn sẽ ước tính phương thức nào trong số những phương pháp này để có chi phí cuộc gọi thấp nhất? Phần mở rộng C có hiệu quả hơn việc sử dụng ctypes không? – CNK

+1

Phần mở rộng C luôn có thể giành chiến thắng vì nó có cơ hội thực hiện nhiều chuyển đổi cùng một lúc (mỗi lần trả về các số trong một danh sách hoặc trong một trình lặp). Phương thức * ctypes * có mức độ chi tiết của một cuộc gọi cho mỗi chuyển đổi. Ngoài ra, bạn không muốn * tất cả * dữ liệu, vì vậy một phần mở rộng C có thể bỏ qua các giá trị không mong muốn, tiết kiệm nhiều chu kỳ chuyển đổi/phân bổ/incref/so sánh/nhảy/decref. –

Các vấn đề liên quan