Python song song cho vòng lặp

Đầu tiên, trong Python, nếu mã của bạn bị ràng buộc bởi CPU, đa luồng sẽ không hữu ích, bởi vì chỉ một luồng có thể giữ Khóa phiên dịch toàn cầu và do đó chạy mã Python tại một thời điểm. Vì vậy, bạn cần sử dụng các quy trình, không phải chủ đề

Nội dung chính Hiển thị

  • Hãy thử nghiệm một số khái niệm này
  • Python có thể chạy nhiều luồng không?
  • Làm thế nào để bạn viết nhiều chủ đề trong Python?
  • Các luồng Python có thể chạy trên nhiều lõi không?
  • Làm thế nào để bạn chạy đồng thời một vòng lặp for trong Python?

Điều này không đúng nếu thao tác của bạn "mất thời gian để quay trở lại" bởi vì nó bị ràng buộc bởi IO—tức là, đang chờ các bản sao trên mạng hoặc đĩa hoặc tương tự. Tôi sẽ quay lại vấn đề đó sau

Tiếp theo, cách xử lý 5 hoặc 10 hoặc 100 mục cùng một lúc là tạo một nhóm gồm 5 hoặc 10 hoặc 100 công nhân và đặt các mục vào hàng đợi mà công nhân phục vụ. May mắn thay, cả hai thư viện stdlib multiprocessingconcurrent.futures đều gói gọn hầu hết các chi tiết cho bạn

Cái trước mạnh hơn và linh hoạt hơn cho lập trình truyền thống; . [Trong trường hợp này, cách triển khai rõ ràng nhất với mỗi cần 3 dòng với

executor = concurrent.futures.ProcessPoolExecutor[10]
futures = [executor.submit[try_my_operation, item] for item in items]
concurrent.futures.wait[futures]
0, 4 dòng với multiprocessing. ]

Nếu bạn đang sử dụng 2. 6-2. 7 hoặc 3. 0-3. 1,

executor = concurrent.futures.ProcessPoolExecutor[10]
futures = [executor.submit[try_my_operation, item] for item in items]
concurrent.futures.wait[futures]
0 không được tích hợp sẵn, nhưng bạn có thể cài đặt nó từ PyPI [
executor = concurrent.futures.ProcessPoolExecutor[10]
futures = [executor.submit[try_my_operation, item] for item in items]
concurrent.futures.wait[futures]
3]

Cuối cùng, việc song song hóa mọi thứ thường đơn giản hơn rất nhiều nếu bạn có thể biến toàn bộ phép lặp vòng lặp thành một lệnh gọi hàm [điều mà bạn có thể, e. g. , chuyển đến

executor = concurrent.futures.ProcessPoolExecutor[10]
futures = [executor.submit[try_my_operation, item] for item in items]
concurrent.futures.wait[futures]
4], vì vậy hãy làm điều đó trước

def try_my_operation[item]:
    try:
        api.my_operation[item]
    except:
        print['error with item']

Để tất cả chúng cùng nhau

executor = concurrent.futures.ProcessPoolExecutor[10]
futures = [executor.submit[try_my_operation, item] for item in items]
concurrent.futures.wait[futures]

Nếu bạn có nhiều công việc tương đối nhỏ, chi phí hoạt động đa xử lý có thể ảnh hưởng đến lợi nhuận. Cách giải quyết đó là gộp công việc thành những công việc lớn hơn. Ví dụ: [sử dụng

executor = concurrent.futures.ProcessPoolExecutor[10]
futures = [executor.submit[try_my_operation, item] for item in items]
concurrent.futures.wait[futures]
0 từ công thức nấu ăn của
executor = concurrent.futures.ProcessPoolExecutor[10]
futures = [executor.submit[try_my_operation, item] for item in items]
concurrent.futures.wait[futures]
1 mà bạn có thể sao chép và dán vào mã của mình hoặc lấy từ dự án
executor = concurrent.futures.ProcessPoolExecutor[10]
futures = [executor.submit[try_my_operation, item] for item in items]
concurrent.futures.wait[futures]
2 trên PyPI]

def try_multiple_operations[items]:
    for item in items:
        try:
            api.my_operation[item]
        except:
            print['error with item']

executor = concurrent.futures.ProcessPoolExecutor[10]
futures = [executor.submit[try_multiple_operations, group] 
           for group in grouper[5, items]]
concurrent.futures.wait[futures]

Cuối cùng, nếu mã của bạn bị ràng buộc IO thì sao? . Đôi khi "ít chi phí hơn" đó đủ để có nghĩa là bạn không cần xử lý theo đợt với các luồng, nhưng bạn thực hiện với các quy trình, đó là một chiến thắng tốt

Vì vậy, làm thế nào để bạn sử dụng các luồng thay vì các quy trình?

Nếu bạn không chắc liệu mã của mình bị ràng buộc bởi CPU hay bị ràng buộc bởi IO, chỉ cần thử cả hai cách

Tôi có thể làm điều này cho nhiều chức năng trong tập lệnh python của mình không? . Có thể thực hiện hai chức năng đa luồng trong cùng một tập lệnh không?

Đúng. Trong thực tế, có hai cách khác nhau để làm điều đó

Đầu tiên, bạn có thể chia sẻ cùng một trình thực thi [luồng hoặc quy trình] và sử dụng nó từ nhiều nơi mà không gặp vấn đề gì. Toàn bộ quan điểm của nhiệm vụ và tương lai là chúng độc lập;

Ngoài ra, bạn có thể có hai người thực thi trong cùng một chương trình mà không gặp vấn đề gì. Điều này có chi phí hiệu suất—nếu bạn đang sử dụng cả hai bộ thực thi cùng một lúc, thì cuối cùng bạn sẽ cố gắng chạy [ví dụ] 16 luồng bận trên 8 lõi, điều đó có nghĩa là sẽ có một số chuyển đổi ngữ cảnh. Nhưng đôi khi nó đáng làm vì chẳng hạn như hai người thực thi hiếm khi bận cùng một lúc và nó làm cho mã của bạn đơn giản hơn rất nhiều. Hoặc có thể một người thực thi đang chạy các tác vụ rất lớn có thể mất một lúc để hoàn thành và người kia đang chạy các tác vụ rất nhỏ cần hoàn thành càng nhanh càng tốt, vì khả năng đáp ứng quan trọng hơn thông lượng cho một phần chương trình của bạn

Nếu bạn không biết cái nào phù hợp với chương trình của mình, thường thì đó là cái đầu tiên

Bao lâu thì chúng ta phải chạy một thao tác tính toán nặng trên một danh sách các đối tượng?

Điểm chung giữa hai vấn đề nêu trên là gì?

Có gì khác nhau?

Vâng, tôi biết. đó là nặng. Hãy khám phá điều này từng phần

CPU là gì?

CPU là bộ xử lý trung tâm. Đó là nó

Đùa thôi, hãy để tôi giải thích thêm một chút. Năng suất của CPU được đo dựa trên các chu kỳ [nhưng nó cũng có thể phụ thuộc vào nhiều yếu tố khác, bao gồm cả kiến ​​trúc] - thời gian cần thiết để thực hiện một thao tác đơn giản của bộ xử lý. Vì vậy, ví dụ: nếu bạn kiểm tra trình quản lý tác vụ trên hệ thống của mình, có nhiều quy trình đang hoạt động trên cùng một CPU, chẳng hạn như Google Chrome, Slack, VSCode, v.v. và họ đang biến nó thành hiện thực bằng cách chia sẻ lượng thời gian mà mỗi chu kỳ của họ chạy. Một phần mềm có thể chạy trong 10 chu kỳ trong khi phần mềm khác chạy trong 5 chu kỳ tiếp theo và phần mềm thứ ba trong 8 chu kỳ tiếp theo và nó lặp lại. Tất cả điều này có vẻ giống như rất nhiều sự chờ đợi và không làm gì đối với phần mềm không chạy, nhưng hãy đoán xem?

Đa xử lý là gì?

Sử dụng nhiều bộ xử lý để chạy một tác vụ. Nó thường là một trường hợp sử dụng hoàn hảo cho các hoạt động liên quan đến CPU. Trong trường hợp của chúng tôi, chúng tôi sẽ tạo các quy trình và cung cấp cho mỗi quy trình một đối tượng từ danh sách mà chúng tôi muốn xử lý. Điều này sẽ dẫn đến xử lý song song và phản hồi nhanh hơn, nhưng cùng một lượng thời gian CPU. Nói một cách đơn giản, nếu chúng ta có 2 mục trong danh sách và mất 20 giây trước đó, thì nhờ đa xử lý, sẽ mất 10 giây [xấp xỉ] nhưng cùng một lượng chu kỳ CPU được chia cho hai quy trình

báo trước. Bộ xử lý không chia sẻ bộ nhớ, do đó, việc chia sẻ biến toàn cục giữa hai quy trình sẽ khó khăn hơn, nhưng có những giải pháp cho vấn đề này nằm ngoài phạm vi của bài viết này

Đa luồng là gì?

Đa luồng trong ngữ cảnh của python giống với việc phân phối công việc cho các công nhân khác nhau trong cùng một bộ xử lý nhưng tất cả chúng không thể hoạt động cùng một lúc. Vì vậy, lợi thế là gì?

Hãy thử nghiệm một số khái niệm này

Chúng tôi sẽ sử dụng Mô-đun Python - đồng thời. tương lai

Nó có các lớp ThreadPoolExcecutor và ProcessPoolExecutor có cùng giao diện và là các lớp con của lớp Executor

Các mẫu mã được chạy trên hệ thống cục bộ của tôi có cấu hình sau

cấu hình hệ thống. Văn bản được đánh dấu cho thấy hệ thống có 6 lõi, mỗi lõi có thể xử lý hai luồng, do đó có 12 bộ xử lý logic. Đơn giản nó có nghĩa là mỗi lõi [đơn vị làm việc] có thể chạy hai luồng nhưng nó không xảy ra đồng thời. Các chủ đề chỉ được lên lịch để chia sẻ các chu kỳ của lõi

Đưa ra dưới đây, là hai mẫu mã có cùng chức năng tính toán chuyên sâu bao gồm nhiều phép biến đổi được áp dụng trên một hình ảnh. Yup, tôi không thể nghĩ ra bất kỳ trường hợp sử dụng nào khác nên đã quyết định thực hiện một loạt nội dung cho một hình ảnh mà không có lý do rõ ràng. Dù sao, mẫu mã với thực thi bình thường chạy trong 456. 551 giây trong khi với đa xử lý, nó hoàn thành trong 236. 995 giây. Ở đây, ProcessPoolExecutor được sử dụng để đa xử lý với 61 công nhân song song. Có một số tham số khác có thể được sử dụng để tùy chỉnh quy trình, tài liệu có thể được tìm thấy tại đây

Chức năng tính toán chuyên sâu được chạy trên một danh sách các hình ảnh với hiệu suất bình thường Chức năng tính toán chuyên sâu được chạy trên một danh sách các hình ảnh sử dụng đa xử lý

Đa luồng được triển khai theo cách tương tự, nhưng hoàn toàn cần thiết vì một lý do khác - quy trình ràng buộc I/O, như đã đề cập ban đầu. Đưa ra dưới đây là một ví dụ về triển khai đa luồng trong đó chúng tôi đang cố đọc hình ảnh từ một thư mục trên hệ thống cục bộ. Tổng thời gian thực hiện cho tác vụ với đa luồng là 0. 3212 giây trong khi không có đa luồng là 0. 3732 giây, đây là một sự khác biệt đáng kể đối với một danh sách rất nhỏ. Ở đây, chúng ta cũng đang sử dụng các hàm từng phần, rất hữu ích khi chúng ta muốn chuyển vào một hàm có nhiều đối số được điền sẵn

Một tính năng hữu ích khác của đồng thời. tương lai là các đối tượng Tương lai được tạo bởi Executor. Gửi đi[]. Các đối tượng tương lai rất giống với lời hứa trong javascript. Một trong những chức năng trong mô-đun là tương lai. as_completed được sử dụng để nhận kết quả đã hoàn thành và do đó phản hồi nhận được có thể không theo thứ tự như đầu vào đã gửi

Đây chỉ là một tổng quan rất ngắn gọn về những gì đang xảy ra bên dưới mui xe và cũng như cách chúng tôi có thể làm cho mã của mình chạy nhanh hơn dễ dàng như thế nào. Mặc dù còn nhiều điều nữa về chủ đề này, tôi hy vọng điều này sẽ giúp bạn bắt đầu. Đây là một bài viết rất hay bao gồm các thông tin chi tiết về ThreadPoolExecutor

Chào bạn, cảm ơn bạn đã dành thời gian đọc bài viết. Tôi là một Kỹ sư Máy học hiện đang khám phá thế giới MLOps cũng như các ngành khác. Tôi sử dụng phương tiện để ghi lại những suy nghĩ của mình về các chủ đề mà tôi quan tâm gần đây. Bạn có thể kết nối với tôi trên LinkedIn và tôi luôn sẵn sàng trò chuyện nhanh. ]

Python có thể chạy nhiều luồng không?

Tóm lại, phân luồng trong Python cho phép tạo nhiều luồng trong một quy trình duy nhất , nhưng do GIL, sẽ không có luồng nào trong số chúng . Phân luồng vẫn là một tùy chọn rất tốt khi chạy đồng thời nhiều tác vụ ràng buộc I/O.

Làm thế nào để bạn viết nhiều chủ đề trong Python?

Để sử dụng đa luồng, chúng ta cần nhập mô-đun luồng trong Chương trình Python. .

nhập luồng

def print_hello[n]

print["Xin chào, bạn bao nhiêu tuổi ", n]

t1 = luồng. Chủ đề [ target = print_hello, args =[18, ]]

Các luồng Python có thể chạy trên nhiều lõi không?

Python KHÔNG phải là ngôn ngữ đơn luồng. Các quy trình Python thường sử dụng một luồng đơn vì GIL. Mặc dù có GIL, các thư viện thực hiện các tác vụ tính toán nặng như numpy, scipy và pytorch đều sử dụng triển khai dựa trên C, cho phép sử dụng nhiều lõi

Chủ Đề