2010-04-13 45 views
72

Tôi muốn song song chương trình Python của mình để nó có thể sử dụng nhiều bộ xử lý trên máy mà nó chạy trên đó. Song song của tôi là rất đơn giản, trong đó tất cả các "luồng" song song của chương trình là độc lập và ghi đầu ra của chúng vào các tệp riêng biệt. Tôi không cần các chủ đề để trao đổi thông tin nhưng nó là bắt buộc mà tôi biết khi các chủ đề kết thúc kể từ khi một số bước của đường ống của tôi phụ thuộc vào đầu ra của họ.quyết định giữa xử lý con, đa xử lý và chuỗi trong Python?

Tính di động là quan trọng, trong đó tôi muốn điều này chạy trên bất kỳ phiên bản Python nào trên Mac, Linux và Windows. Với những ràng buộc này, đó là mô-đun Python thích hợp nhất để thực hiện điều này? Tôi đang cố gắng để quyết định giữa thread, subprocess, và multiprocessing, mà tất cả dường như cung cấp chức năng liên quan.

Bất kỳ suy nghĩ nào về điều này? Tôi muốn giải pháp đơn giản nhất là di động.

+0

Liên quan: http://stackoverflow.com/questions/1743293/why-does-my-python-program-average-only-33-cpu-per-process-how-can-i-make-pytho/1743312 # 1743312 (đọc câu trả lời của tôi ở đó để xem lý do tại sao chủ đề là không khởi động cho mã thuần-Python) –

+1

"Bất kỳ phiên bản Python" là FAR quá mơ hồ. Python 2.3? 1.x? 3.x? Nó chỉ đơn giản là một điều kiện không thể thỏa mãn. – detly

Trả lời

46

multiprocessing là loại mô-đun dao tuyệt vời của quân đội Thụy Sĩ. Nó tổng quát hơn các luồng, vì bạn thậm chí có thể thực hiện các phép tính từ xa. Điều này là do đó các mô-đun tôi sẽ đề nghị bạn sử dụng.

Mô-đun subprocess cũng sẽ cho phép bạn khởi chạy nhiều quy trình, nhưng tôi thấy nó ít thuận tiện để sử dụng hơn mô-đun đa xử lý mới.

Chủ đề nổi tiếng là tinh tế, và với CPython, bạn thường bị giới hạn ở một lõi, với chúng (mặc dù, như đã nêu trong một trong các nhận xét, Khóa thông dịch toàn cầu (GIL) có thể được phát hành trong mã C từ mã Python).

Tôi tin rằng hầu hết các chức năng của ba mô-đun bạn trích dẫn đều có thể được sử dụng theo cách độc lập với nền tảng. Về mặt di động, lưu ý rằng multiprocessing chỉ có tiêu chuẩn từ Python 2.6 (một phiên bản cho một số phiên bản cũ hơn của Python không tồn tại, mặc dù). Nhưng đó là một mô-đun tuyệt vời!

+1

để gán, tôi chỉ sử dụng mô-đun "đa xử lý" và phương thức pool.map() của nó. miếng bánh ! – kmonsoor

+2

Tại sao lại là downvote? – EOL

3

Để sử dụng nhiều bộ xử lý trong CPython, chỉ là mô-đun multiprocessing. CPython giữ một khóa trên đó là nội bộ (các GIL) mà ngăn chặn chủ đề trên cpus khác để làm việc song song. Mô-đun multiprocessing tạo các quy trình mới (như subprocess) và quản lý liên lạc giữa chúng.

+4

Điều đó không đúng, AFAIK bạn có thể giải phóng GIL bằng cách sử dụng API C, và có những triển khai khác của Python như IronPython hoặc Jython không bị hạn chế như vậy. Tôi đã không downvote mặc dù. –

3

Trong trường hợp tương tự, tôi đã chọn các quy trình riêng biệt và một chút ổ cắm mạng truyền thông cần thiết. Nó có tính di động cao và khá đơn giản để sử dụng python, nhưng có lẽ không đơn giản hơn (trong trường hợp của tôi, tôi cũng có một ràng buộc khác: giao tiếp với các quy trình khác được viết bằng C++).

Trong trường hợp của bạn, tôi có lẽ sẽ đi cho đa xử lý, như chủ đề python, ít nhất là khi sử dụng CPython, không phải là chủ đề thực sự. Vâng, chúng là các luồng hệ thống gốc nhưng các mô-đun C được gọi từ Python có thể hoặc không thể giải phóng GIL và cho phép các luồng khác mà chúng chạy khi gọi mã chặn.

1

Shell ra và để cho các unix ra để làm công việc của bạn:

sử dụng iterpipes quấn subprocess và sau đó:

From Ted Ziuba's site

INPUTS_FROM_YOU | xargs -n1 -0 -P NUM./ Quá trình # NUM quá trình song song

HOẶC

Gnu Parallel cũng sẽ phục vụ

Bạn đi chơi với GIL khi bạn gửi các chàng trai hậu trường ra để làm việc đa lõi của bạn.

+6

"Tính di động là quan trọng, trong đó tôi muốn điều này chạy trên bất kỳ phiên bản Python nào trên Mac, Linux và Windows." – detly

+0

Với giải pháp này, bạn có thể tương tác nhiều lần với công việc không? Bạn có thể làm điều này trong đa xử lý, nhưng tôi không nghĩ như vậy trong tiến trình con. – abalter

126

Đối với tôi đây là thực sự khá đơn giản:

Các subprocess tùy chọn:

subprocesscho chạy file thực thi khác --- nó là cơ bản một wrapper xung quanh os.fork()os.execve() với một số hỗ trợ cho các tùy chọn (Rõ ràng là các cơ chế truyền thông giữa các hệ điều hành (IPC) khác, chẳng hạn như ổ cắm, bộ nhớ chia sẻ SysV và hàng đợi tin nhắn có thể được sử dụng --- nhưng thường bạn đang sử dụng tiến trình con để chạy thứ ba bên nhị phân thực thi một d sẽ bị kẹt với bất kỳ giao diện nào và IPC hỗ trợ các kênh đó).

Thường sử dụng subprocess đồng bộ --- chỉ cần gọi một số tiện ích bên ngoài và đọc lại kết quả hoặc chờ kết quả (có thể đọc kết quả từ tệp tạm thời hoặc sau khi đăng chúng lên cơ sở dữ liệu).

Tuy nhiên, người ta có thể sinh ra hàng trăm quy trình con và thăm dò ý kiến ​​chúng. Tiện ích yêu thích cá nhân của riêng tôi thực hiện chính xác điều đó. Bất lợi lớn nhất của mô-đun subprocess là hỗ trợ I/O thường chặn. Có một bản nháp PEP-3145 để khắc phục điều đó trong một số phiên bản tương lai của Python 3.x và một thay thế asyncproc (Cảnh báo dẫn đến tải xuống, không phải bất kỳ loại tài liệu nào cũng như README). Tôi cũng thấy rằng chỉ cần nhập fcntl và thao tác trực tiếp các mô tả tệp PIPE Popen PIPE của bạn --- mặc dù tôi không biết liệu đây có phải là phần mềm di động cho nền tảng không phải UNIX hay không.

subprocesshầu như không có sự kiện xử lý hỗ trợ ... bạn có thể sử dụng các mô-đun signal và đồng bằng cũ-trường tín hiệu UNIX/Linux --- giết chết quá trình của bạn nhẹ nhàng, như nó được.

Các đa tùy chọn:

multiprocessingđể chạy chức năng trong hiện tại của bạn (Python) mã với sự hỗ trợ cho truyền thông linh hoạt hơn trong các gia đình của các quá trình. Đặc biệt, tốt nhất bạn nên tạo multiprocessing IPC xung quanh các đối tượng của Queue của mô-đun nếu có thể, nhưng bạn cũng có thể sử dụng các đối tượng Event và nhiều tính năng khác (một số trong số đó có thể được hỗ trợ trên các nền tảng hỗ trợ đủ).

mô-đun multiprocessing Python được thiết kế để cung cấp các giao diện và các tính năng mà rất tương tự nhưthreading trong khi cho phép CPython quy mô xử lý của mình cho nhiều CPU/lõi bất chấp sự GIL (Global Interpreter Lock). Nó thúc đẩy tất cả các nỗ lực khóa và kết nối SMP hạt mịn được thực hiện bởi các nhà phát triển hạt nhân hệ điều hành của bạn.

Các luồng tùy chọn:

threadingcho một phạm vi tương đối hẹp của các ứng dụng đó là I/O bound (không cần phải mở rộng trên nhiều lõi CPU) và được hưởng lợi từ các cực thấp độ trễ và chuyển đổi chi phí của chuyển đổi luồng (với bộ nhớ lõi được chia sẻ) so với chuyển đổi quy trình/ngữ cảnh. Trên Linux, đây gần như là bộ trống (thời gian chuyển đổi của quá trình Linux cực kỳ gần với các trình chuyển đổi luồng).

threading bị hai nhược điểm chính trong Python.

Một, tất nhiên, là thực hiện cụ thể --- chủ yếu ảnh hưởng đến CPython. Đó là GIL. Đối với hầu hết các phần, hầu hết các chương trình CPython sẽ không được hưởng lợi từ sự sẵn có của nhiều hơn hai CPU (lõi) và thường hiệu suất sẽ bị từ GIL khóa ganh đua.

Vấn đề lớn hơn không thực hiện cụ thể, là các chủ đề chia sẻ cùng bộ nhớ, bộ xử lý tín hiệu, bộ mô tả tệp và một số tài nguyên hệ điều hành khác. Vì vậy, lập trình viên phải cực kỳ cẩn thận về khóa đối tượng, xử lý ngoại lệ và các khía cạnh khác của mã của chúng vừa tinh tế vừa có thể giết chết, ngăn chặn hoặc bế tắc toàn bộ quá trình (bộ chủ đề).

Bằng cách so sánh mô hình multiprocessing cho mỗi quá trình bộ nhớ riêng, bộ mô tả tệp, v.v. Một ngoại lệ lỗi hoặc không được giải quyết trong bất kỳ một trong số chúng sẽ chỉ giết tài nguyên đó và xử lý mạnh mẽ sự biến mất của quá trình con hoặc anh chị em. dễ dàng hơn gỡ lỗi, cách ly và sửa chữa hoặc làm việc xung quanh các vấn đề tương tự trong chuỗi.

  • (Lưu ý: sử dụng threading với các hệ thống Python lớn, chẳng hạn như NumPy, có thể vơi bớt khổ đau đáng kể từ GIL tranh sau đó hầu hết các mã Python của riêng bạn sẽ Đó là bởi vì họ đã được thiết kế đặc biệt để làm như vậy.).

Các xoắn tùy chọn:

Nó cũng đáng chú ý là Twisted cung cấp thêm một lựa chọn đó là cả thanh lịch và rất khó khăn để hiểu. Về cơ bản, với nguy cơ đơn giản hóa đến mức người hâm mộ của Twisted có thể xông vào nhà tôi với những cái chĩa và ngọn đuốc, Twisted cung cấp và phối hợp nhiều tác vụ theo sự kiện trong bất kỳ quá trình nào.

Để hiểu thế nào điều này có thể ta nên đọc về các tính năng của select() (có thể được xây dựng xung quanh các chọn() hoặc cuộc thăm dò() hoặc tương tự hệ thống hệ điều hành các cuộc gọi). Về cơ bản, tất cả đều được thúc đẩy bởi khả năng đưa ra yêu cầu của hệ điều hành để ngủ trong khi chờ bất kỳ hoạt động nào trên danh sách các bộ mô tả tệp hoặc một số thời gian chờ.

Đánh thức từ mỗi cuộc gọi này đến select() là sự kiện --- có thể có một số đầu cắm hoặc bộ mô tả tệp hoặc không gian đệm có sẵn trên một số bộ mô tả hoặc ổ cắm khác (có thể ghi) một số điều kiện đặc biệt (ví dụ như các gói PUSH'd out-of-band), hoặc một TIMEOUT.

Vì vậy, mô hình lập trình xoắn được xây dựng xung quanh việc xử lý các sự kiện này, sau đó lặp trên trình xử lý "chính", cho phép nó gửi các sự kiện tới trình xử lý của bạn.

Cá nhân tôi nghĩ rằng cái tên đó, Twisted như gợi nhiều liên tưởng của mô hình lập trình ... từ cách tiếp cận của mình vào vấn đề phải, trong một nghĩa nào đó, "xoắn" từ trong ra ngoài. Thay vì thụ thai chương trình của bạn như một loạt các hoạt động trên dữ liệu đầu vào và kết quả đầu ra hoặc kết quả, bạn đang viết chương trình của bạn như một dịch vụ hoặc daemon và xác định cách nó phản ứng với các sự kiện khác nhau. (Trong thực tế cốt lõi "vòng lặp chính" của một chương trình Twisted là (thường? Luôn?) Một reactor().

Các thách thức lớn cho việc sử dụng Twisted liên quan đến xoắn tâm trí của bạn xung quanh mô hình sự kiện thúc đẩy và cũng tránh sử dụng các Đây là lý do tại sao Twisted cung cấp các mô-đun riêng của mình để xử lý giao thức SSH, cho các lời nguyền, và các hàm xử lý con/popen của chính nó, và nhiều mô-đun và trình xử lý giao thức khác , lúc đầu đỏ mặt, dường như sẽ sao chép mọi thứ trong thư viện chuẩn của Python

Tôi nghĩ rằng hữu ích khi hiểu Twisted ở mức khái niệm ngay cả khi bạn không bao giờ định sử dụng nó. e thông tin chi tiết về hiệu suất, tranh chấp và xử lý sự kiện trong quá trình xử lý, xử lý đa xử lý và xử lý con cũng như bất kỳ quá trình xử lý phân tán nào mà bạn thực hiện.

(Lưu ý: phiên bản mới hơn của Python 3.x đã bao gồm asyncio (không đồng bộ I/O) tính năng như async def, các @ async.coroutine trang trí, và chờ từ khóa, và năng suất từ ​​tương lai Hỗ trợ. Tất cả đều tương tự như Xoắn từ phối cảnh quá trình (phối hợp đa tác vụ)).

Các phân phối tùy chọn:

Tuy nhiên, một lĩnh vực chế biến bạn chưa được hỏi về, nhưng đó là giá trị xem xét, đó là của phân phối chế biến. Có nhiều công cụ và khung công tác Python để xử lý phân tán và tính toán song song. Cá nhân tôi cho rằng cách dễ nhất để sử dụng là điều ít được coi là thường xuyên nhất trong không gian đó.

Nó gần như là tầm thường để xây dựng xử lý phân tán xung quanh Redis. Toàn bộ kho khóa có thể được sử dụng để lưu trữ các đơn vị công việc và kết quả, Redis LIST có thể được sử dụng như Queue() như đối tượng và hỗ trợ PUB/SUB có thể được sử dụng để xử lý giống như Event. Bạn có thể băm khóa và sử dụng các giá trị của bạn, được sao chép trên một nhóm các trường hợp Redis, để lưu trữ cấu trúc liên kết và ánh xạ mã thông báo băm để cung cấp băm đồng nhất và thất bại cho việc mở rộng vượt quá khả năng của bất kỳ cá thể đơn lẻ nào để phối hợp công nhân của bạn và dữ liệu marshaling (ngâm, JSON, BSON hoặc YAML) trong số đó.

Tất nhiên khi bạn bắt đầu để xây dựng một quy mô lớn hơn và giải pháp phức tạp hơn xung quanh Redis bạn lại thực hiện rất nhiều các tính năng đã được giải quyết bằng, Celery, Apache SparkHadoop, Zookeeper, etcd, Cassandra và vân vân . Những alll đó có các mô-đun để truy cập Python vào các dịch vụ của chúng.

[Cập nhật: Một vài tài nguyên để xem xét nếu bạn đang xem xét Python để tính toán chuyên sâu trên các hệ thống phân tán: IPython ParallelPySpark. Mặc dù đây là những hệ thống tính toán phân tán theo mục đích chung, chúng là các phân tích và phân tích dữ liệu hệ thống con đặc biệt có thể truy cập và phổ biến].

Kết luận

Ở đó bạn có gam màu của các lựa chọn thay thế chế biến cho Python, từ ren duy nhất, với các cuộc gọi đơn giản để đồng bộ quy trình con, vũng subprocesses thăm dò, luồng và đa, hướng sự kiện hợp tác đa nhiệm vụ, và ra để xử lý phân tán.

+1

Rất khó để sử dụng đa xử lý với các lớp/OOP. – Tjorriemorrie

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