Python đa xử lý số lượng quy trình tối ưu

Mọi người có thể sử dụng nhiều thời gian hơn, đặc biệt là tại Viện đô thị, nơi các nhà nghiên cứu thường xuyên phân tích các tập dữ liệu lớn. Vì chúng tôi không thể tạo ra thời gian, nhóm lập trình nghiên cứu tập trung vào việc làm cho các khía cạnh tự động của quy trình nghiên cứu trở nên nhanh hơn. Nhiều công cụ của chúng tôi sử dụng Python, một ngôn ngữ lập trình giúp dễ dàng phân tích dữ liệu thông qua các công cụ như pandas và NumPy nhưng thường chậm hơn các ngôn ngữ được biên dịch như C/C++ hoặc Fortran. Tuy nhiên, một số kỹ thuật có thể cải thiện tốc độ của chương trình Python, thường là đáng kể. Trong bài đăng này, chúng tôi thảo luận về cách Urban sử dụng đa xử lý để tăng tốc mã Python

Các ngôn ngữ lập trình nghiên cứu phổ biến chỉ sử dụng một bộ xử lý

“Đa” trong đa xử lý đề cập đến nhiều lõi trong bộ xử lý trung tâm (CPU) của máy tính. Máy tính ban đầu chỉ có một lõi CPU hoặc bộ xử lý, là đơn vị giúp thực hiện tất cả các phép tính toán học của chúng ta. Ngày nay, các máy tính thường có từ 2 đến 128 lõi, nghĩa là việc tận dụng nhiều hơn một lõi có thể cải thiện đáng kể thời gian xử lý

Hầu hết các chương trình và ngôn ngữ lập trình không tận dụng lợi thế của nhiều lõi. Các ngôn ngữ lập trình Java và C tự động gửi các tác vụ đến nhiều CPU cùng một lúc, nhưng các nhà nghiên cứu ở Đô thị chủ yếu sử dụng Stata và SAS, với số lượng ngày càng tăng sử dụng R và Python. Các ngôn ngữ “cấp cao hơn” này đi kèm với các gói và chức năng vượt trội giúp làm việc với dữ liệu dễ dàng hơn, nhưng các ngôn ngữ này cũng mặc định chỉ sử dụng một lõi, ngay cả trong các máy có sẵn nhiều CPU. Bằng cách chỉ sử dụng lõi đơn đó, các ngôn ngữ lập trình này kém hiệu quả hơn

Trong Python, việc sử dụng một CPU là do khóa trình thông dịch toàn cầu (GIL), chỉ cho phép một luồng mang trình thông dịch Python tại bất kỳ thời điểm nào. GIL được triển khai để xử lý sự cố quản lý bộ nhớ, nhưng kết quả là Python bị hạn chế sử dụng một bộ xử lý duy nhất

Đa xử lý có thể cải thiện đáng kể tốc độ xử lý

Bỏ qua GIL khi thực thi mã Python cho phép mã chạy nhanh hơn vì giờ đây chúng ta có thể tận dụng lợi thế của đa xử lý. Mô-đun đa xử lý tích hợp sẵn của Python cho phép chúng tôi chỉ định một số phần mã nhất định để bỏ qua GIL và gửi mã tới nhiều bộ xử lý để thực thi đồng thời

Trong ví dụ đơn giản này, giả sử cả ba luồng có thời gian chạy giống hệt nhau, giải pháp đa xử lý sẽ cắt giảm một phần ba tổng thời gian thực hiện. Tuy nhiên, mức giảm này không tương ứng chính xác với số lượng bộ xử lý có sẵn do chi phí liên quan đến việc tạo ra các quy trình đa xử lý, nhưng mức tăng thể hiện sự cải thiện đáng kể so với các hoạt động đơn lõi

Ba yêu cầu đối với đa xử lý

Trước khi bạn có thể bắt đầu đa xử lý, bạn cần chọn phần mã nào để đa xử lý. Các phần mã này phải đáp ứng các tiêu chí sau

1. Không được phụ thuộc vào kết quả trước đó

2. Không cần phải được thực hiện theo một thứ tự cụ thể

3. Không trả lại bất cứ thứ gì cần được truy cập sau này trong mã

Ví dụ: một phần của hệ thống điện toán đám mây đang được phát triển với sự tài trợ của Alfred P. Sloan Foundation đang chạy các mô hình vi mô của Trung tâm Chính sách Thuế phải thực hiện một số chức năng trên mỗi mục của một danh sách khá lớn. Phần mã được đề cập lấy một danh sách dữ liệu lớn và chạy từng mục dữ liệu thông qua phân tích và định dạng. Mã này độc lập với phần còn lại của chương trình. Nó không cần biết kết quả của dữ liệu đã phân tích trước đó để thực hiện công việc của mình và dữ liệu mà nó phân tích không được sử dụng trong phần còn lại của mã. Nếu các phần này yêu cầu đầu vào từ nhau, khung đa xử lý - trong đó các phần khác nhau được chạy song song - sẽ bị phá vỡ. (Có nhiều cách giải quyết vấn đề này, nhưng điều đó nằm ngoài phạm vi của bài đăng này. )

Đây là một phần mã con đơn giản hơn, là ứng cử viên chính cho đa xử lý

Vòng lặp for truyền thống đi qua từng danh sách một và thực hiện các chức năng trên từng mục riêng lẻ. Trong mô hình này, các vòng chỉ sử dụng 30 đến 40 phần trăm năng lượng CPU có sẵn. Nếu chúng ta sử dụng đa xử lý, chức năng này sẽ được thực thi trên nhiều mục danh sách cùng một lúc và có thể sử dụng tối đa 100% CPU trên máy đa lõi. Trên hết, chúng ta sẽ thấy thời gian thực hiện giảm đáng kể

Cách sử dụng đa xử lý. Lớp Process và lớp Pool

Mô-đun Python đa xử lý chứa hai lớp có khả năng xử lý các tác vụ. Lớp Process gửi từng tác vụ đến một bộ xử lý khác nhau và lớp Pool gửi các nhóm tác vụ đến các bộ xử lý khác nhau. Chúng tôi sẽ chỉ ra cách đa xử lý mã ví dụ bằng cách sử dụng cả hai lớp. Mặc dù cả hai lớp đều cung cấp tốc độ tăng tương tự, nhưng lớp Quy trình hiệu quả hơn trong trường hợp này vì không có nhiều quy trình để thực thi. Nhóm hữu ích nhất đối với số lượng lớn quy trình trong đó mỗi quy trình có thể thực thi nhanh chóng, trong khi Quy trình hữu ích nhất đối với một số lượng nhỏ quy trình trong đó mỗi quy trình sẽ mất nhiều thời gian hơn để thực thi

Để sử dụng lớp Quy trình, hãy đặt các hàm và phép tính được thực hiện trên từng mục danh sách trong hàm riêng của nó. Chức năng này sẽ lấy một mục danh sách làm một trong các đối số của nó. Tiếp theo, nhập mô-đun đa xử lý, tạo quy trình mới cho từng mục danh sách và kích hoạt từng quy trình trong một cuộc gọi. Chúng tôi theo dõi các quy trình này bằng cách tạo một danh sách và thêm từng quy trình vào danh sách đó. Sau khi tạo tất cả các quy trình, lấy đầu ra riêng biệt của từng CPU và nối chúng thành một danh sách

Để sử dụng lớp Pool, chúng ta cũng phải tạo một hàm riêng biệt lấy một mục danh sách làm đối số giống như chúng ta đã làm khi sử dụng Process. Sau đó, sử dụng mô-đun đa xử lý, tạo một đối tượng Pool có tên là pool. Đối tượng này có một chức năng được gọi là map, nhận chức năng mà chúng ta muốn đa xử lý và danh sách làm đối số, sau đó lặp qua danh sách cho chức năng đó. Sau khi gọi hàm map, hãy đóng đối tượng để cho phép tắt hoàn toàn

Trừ khi bạn đang chạy một máy có hơn 10 bộ xử lý, mã Quy trình sẽ chạy nhanh hơn mã Nhóm. Quá trình gửi mã đến bộ xử lý ngay khi quá trình bắt đầu. Nhóm gửi mã tới từng bộ xử lý có sẵn và không gửi nữa cho đến khi bộ xử lý tính toán xong phần mã đầu tiên. Nhóm làm điều này để các quy trình không phải cạnh tranh tài nguyên máy tính, nhưng điều này làm cho nó chậm hơn Quy trình trong trường hợp mỗi quy trình dài. Đối với một ví dụ trong đó Pool nhanh hơn Process, hãy xóa dòng time.sleep(2) trong multiprocessing_func trong cả mã Process và Pool

Mã đa xử lý không thực thi theo thứ tự như thực thi nối tiếp. Không có gì đảm bảo rằng quy trình đầu tiên được tạo sẽ là quy trình đầu tiên bắt đầu hoặc hoàn thành. Do đó, mã đa xử lý thường thực thi theo một thứ tự khác nhau mỗi lần chạy, ngay cả khi mỗi kết quả luôn giống nhau

Với đa xử lý, sử dụng ngôn ngữ lập trình cấp cao hơn không nhất thiết phải hy sinh tốc độ. Một số khía cạnh của mã có thể được chạy song song, điều này cho phép chúng tôi thực hiện công việc của mình nhanh hơn và hiệu quả hơn. Nhờ đa xử lý, chúng tôi đã cắt giảm thời gian chạy mã hệ thống điện toán đám mây từ hơn 40 giờ xuống chỉ còn 6 giờ. Trong một dự án khác, chúng tôi đã cắt giảm thời gian chạy từ 500 giờ xuống chỉ còn 4 giờ trên máy 128 lõi

Để biết thêm thông tin giới thiệu về đa xử lý trong Python, hãy xem hướng dẫn này hoặc bài đăng trên blog này

Có bao nhiêu quy trình nên chạy đa xử lý Python?

Nếu chúng tôi đang sử dụng trình quản lý ngữ cảnh để tạo nhóm quy trình để nó tự động tắt, thì bạn có thể định cấu hình số lượng quy trình theo cách tương tự. Số lượng công nhân phải nhỏ hơn hoặc bằng 61 nếu Windows là hệ điều hành của bạn .

Đa xử lý Python có thể sử dụng bao nhiêu luồng?

Mỗi lõi CPU có thể có tối đa hai luồng nếu CPU của bạn đã bật đa/siêu phân luồng. Bạn có thể tìm kiếm bộ xử lý CPU của riêng bạn để tìm hiểu thêm.

Đa xử lý có làm cho Python nhanh hơn không?

Bạn có thể tăng tốc độ thực thi chương trình của mình bằng cách sử dụng đa xử lý bằng cách chạy song song nhiều tác vụ mở rộng của CPU . Bạn có thể tạo và quản lý các quy trình bằng mô-đun đa xử lý. Bạn có thể tạo và quản lý các quy trình theo cách tốt hơn bằng cách sử dụng bộ thực thi nhóm quy trình đồng thời.

Có bao nhiêu quy trình có thể có được một phiên bản khóa đa xử lý đồng thời?

Mỗi lần chỉ có một quy trình có thể lấy được khóa và sau khi thực hiện xong, chúng sẽ báo cáo một thông báo bao gồm id của mình và thời gian chúng sẽ ngủ.