Cách chạy nhiều tiến trình trong python

Tăng tốc độ tính toán là mục tiêu mà ai cũng muốn đạt được. Điều gì sẽ xảy ra nếu bạn có một tập lệnh có thể chạy nhanh hơn mười lần so với thời gian chạy hiện tại của nó? . Chúng ta sẽ nói về đa xử lý là gì, ưu điểm của nó và cách cải thiện thời gian chạy chương trình Python của bạn bằng cách sử dụng lập trình song song

Được rồi, vậy chúng ta hãy đi

Giới thiệu về song song

Trước khi đi sâu vào mã Python, chúng ta phải nói về điện toán song song, đây là một khái niệm quan trọng trong khoa học máy tính

Thông thường, khi bạn chạy tập lệnh Python, mã của bạn tại một thời điểm nào đó sẽ trở thành một quy trình và quy trình này sẽ chạy trên một lõi CPU của bạn. Nhưng các máy tính hiện đại có nhiều hơn một lõi, vậy nếu bạn có thể sử dụng nhiều lõi hơn cho các tính toán của mình thì sao?

Bây giờ chúng ta hãy coi đây là nguyên tắc chung, nhưng sau này, trong bài viết này, chúng ta sẽ thấy rằng điều này không đúng một cách phổ biến

Không đi vào quá nhiều chi tiết, ý tưởng đằng sau tính song song là viết mã của bạn theo cách nó có thể sử dụng nhiều lõi của CPU

Để làm cho mọi thứ dễ dàng hơn, hãy xem một ví dụ

Điện toán song song và nối tiếp

Hãy tưởng tượng bạn có một vấn đề lớn cần giải quyết và bạn chỉ có một mình. Bạn cần tính căn bậc hai của tám số khác nhau. Bạn làm nghề gì? . Bạn bắt đầu với số đầu tiên và bạn tính kết quả. Sau đó, bạn tiếp tục với những người khác

Điều gì sẽ xảy ra nếu bạn có ba người bạn giỏi toán sẵn sàng giúp đỡ bạn? . Điều này có nghĩa là vấn đề của bạn sẽ được giải quyết nhanh hơn

Được rồi, như vậy tất cả rõ ràng? . Trong ví dụ đầu tiên, toàn bộ nhiệm vụ được bạn giải quyết tuần tự. Điều này được gọi là tính toán nối tiếp. Trong ví dụ thứ hai, vì bạn đang làm việc với tổng cộng bốn lõi, nên bạn đang sử dụng tính toán song song. Tính toán song song liên quan đến việc sử dụng các quy trình hoặc quy trình song song được phân chia giữa nhiều lõi trong bộ xử lý

Mô hình lập trình song song

Chúng tôi đã thiết lập lập trình song song là gì, nhưng chúng tôi sử dụng nó như thế nào? . Có một số câu hỏi mà bạn nên xem xét trước khi tiếp cận song song hóa. Ví dụ: có bất kỳ tối ưu hóa nào khác có thể tăng tốc độ tính toán của chúng tôi không?

Hiện tại, hãy chấp nhận rằng song song hóa là giải pháp tốt nhất cho bạn. Có ba mô hình chủ yếu trong điện toán song song

  • hoàn toàn song song. Các tác vụ có thể được chạy độc lập và chúng không cần giao tiếp với nhau
  • Bộ nhớ chia sẻ song song. Các quy trình [hoặc luồng] cần giao tiếp, vì vậy chúng chia sẻ một không gian địa chỉ chung
  • Thông qua. Các tiến trình cần chia sẻ thông điệp khi cần

Trong bài viết này, chúng tôi sẽ minh họa mô hình đầu tiên, cũng là mô hình đơn giản nhất

Đa xử lý Python. Xử lý song song dựa trên quy trình trong Python

Một cách để đạt được tính song song trong Python là sử dụng mô-đun đa xử lý. Mô-đun

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
1 cho phép bạn tạo nhiều quy trình, mỗi quy trình có trình thông dịch Python riêng. Vì lý do này, đa xử lý Python thực hiện song song dựa trên quy trình

Bạn có thể đã nghe nói về các thư viện khác, chẳng hạn như

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
3, cũng được tích hợp sẵn trong Python, nhưng có những điểm khác biệt quan trọng giữa chúng. Mô-đun
from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
1 tạo quy trình mới, trong khi
from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
3 tạo chủ đề mới

Trong phần tiếp theo, chúng ta sẽ xem xét những lợi ích của việc sử dụng đa xử lý

Lợi ích của việc sử dụng đa xử lý

Dưới đây là một vài lợi ích của đa xử lý

  • sử dụng CPU tốt hơn khi xử lý các tác vụ sử dụng nhiều CPU
  • kiểm soát nhiều hơn đối với một đứa trẻ so với chủ đề
  • dễ viết mã

Ưu điểm đầu tiên liên quan đến hiệu suất. Vì đa xử lý tạo ra các quy trình mới, bạn có thể sử dụng hiệu quả hơn sức mạnh tính toán của CPU bằng cách phân chia nhiệm vụ của mình cho các lõi khác. Hầu hết các bộ xử lý hiện nay đều là bộ xử lý đa lõi và nếu bạn tối ưu hóa mã của mình, bạn có thể tiết kiệm thời gian bằng cách giải các phép tính song song

Ưu điểm thứ hai xem xét một giải pháp thay thế cho đa xử lý, đó là đa luồng. Tuy nhiên, các luồng không phải là các quy trình và điều này có hậu quả của nó. Nếu bạn tạo một luồng, sẽ rất nguy hiểm khi tắt nó hoặc thậm chí làm gián đoạn nó như bạn làm với một quy trình bình thường. Vì việc so sánh giữa đa xử lý và đa luồng không nằm trong phạm vi của bài viết này, tôi khuyến khích bạn đọc thêm về nó

Ưu điểm thứ ba của đa xử lý là nó khá dễ triển khai, do tác vụ bạn đang cố xử lý phù hợp với lập trình song song

Bắt đầu với Đa xử lý Python

Cuối cùng thì chúng ta cũng đã sẵn sàng để viết một số mã Python

Chúng tôi sẽ bắt đầu với một ví dụ rất cơ bản và chúng tôi sẽ sử dụng nó để minh họa các khía cạnh cốt lõi của đa xử lý Python. Trong ví dụ này, chúng ta sẽ có hai quy trình

  • Quá trình
    from multiprocessing import Pool
    import time
    import math
    
    N = 5000000
    
    def cube[x]:
        return math.sqrt[x]
    
    if __name__ == "__main__":
        with Pool[] as pool:
          result = pool.map[cube, range[10,N]]
        print["Program finished!"]
    
    0. Chỉ có một tiến trình cha, có thể có nhiều tiến trình con
  • Quá trình
    from multiprocessing import Pool
    import time
    import math
    
    N = 5000000
    
    def cube[x]:
        return math.sqrt[x]
    
    if __name__ == "__main__":
        with Pool[] as pool:
          result = pool.map[cube, range[10,N]]
        print["Program finished!"]
    
    1. Điều này được sinh ra bởi cha mẹ. Mỗi đứa trẻ cũng có thể có con mới

Chúng tôi sẽ sử dụng quy trình

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
1 để thực hiện một chức năng nhất định. Bằng cách này,
from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
0 có thể tiếp tục thực hiện

Một ví dụ đa xử lý Python đơn giản

Đây là mã chúng tôi sẽ sử dụng cho ví dụ này

from multiprocessing import Process

def bubble_sort[array]:
    check = True
    while check == True:
      check = False
      for i in range[0, len[array]-1]:
        if array[i] > array[i+1]:
          check = True
          temp = array[i]
          array[i] = array[i+1]
          array[i+1] = temp
    print["Array sorted: ", array]

if __name__ == '__main__':
    p = Process[target=bubble_sort, args=[[1,9,4,5,2,6,8,4],]]
    p.start[]
    p.join[]

Trong đoạn mã này, chúng ta đã định nghĩa một hàm có tên là

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
4. Chức năng này là một triển khai thực sự ngây thơ của thuật toán sắp xếp Bubble Sort. Nếu bạn không biết nó là gì, đừng lo lắng, vì nó không quan trọng lắm. Điều quan trọng cần biết là đó là một chức năng thực hiện một số công việc

Lớp quy trình

Từ

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
1, chúng tôi nhập lớp
from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
6. Lớp này đại diện cho một hoạt động sẽ được chạy trong một quy trình riêng biệt. Thật vậy, bạn có thể thấy rằng chúng tôi đã thông qua một số đối số

  • from multiprocessing import Pool
    import time
    import math
    
    N = 5000000
    
    def cube[x]:
        return math.sqrt[x]
    
    if __name__ == "__main__":
        with Pool[] as pool:
          result = pool.map[cube, range[10,N]]
        print["Program finished!"]
    
    7, nghĩa là quy trình mới của chúng ta sẽ chạy hàm
    from multiprocessing import Pool
    import time
    import math
    
    N = 5000000
    
    def cube[x]:
        return math.sqrt[x]
    
    if __name__ == "__main__":
        with Pool[] as pool:
          result = pool.map[cube, range[10,N]]
        print["Program finished!"]
    
    8
  • from multiprocessing import Pool
    import time
    import math
    
    N = 5000000
    
    def cube[x]:
        return math.sqrt[x]
    
    if __name__ == "__main__":
        with Pool[] as pool:
          result = pool.map[cube, range[10,N]]
        print["Program finished!"]
    
    9, là mảng được truyền làm đối số cho hàm đích

Khi chúng tôi đã tạo một thể hiện cho lớp Quy trình, chúng tôi chỉ cần bắt đầu quy trình. Điều này được thực hiện bằng cách viết

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
00. Tại thời điểm này, quá trình bắt đầu

Trước khi thoát, chúng ta cần đợi tiến trình con hoàn thành việc tính toán của nó. Phương thức

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
01 chờ quá trình kết thúc

Trong ví dụ này, chúng tôi chỉ tạo một tiến trình con. Như bạn có thể đoán, chúng ta có thể tạo nhiều tiến trình con hơn bằng cách tạo nhiều thể hiện hơn trong lớp

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
6

lớp bi-a

Điều gì sẽ xảy ra nếu chúng ta cần tạo nhiều quy trình để xử lý các tác vụ sử dụng nhiều CPU hơn?

Lớp

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
03 cho phép bạn tạo một nhóm quy trình worker và trong ví dụ sau, chúng ta sẽ xem cách chúng ta có thể sử dụng nó. Đây là ví dụ mới của chúng tôi

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]

Trong đoạn mã này, chúng ta có một hàm

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
05 chỉ cần lấy một số nguyên và trả về căn bậc hai của nó. Dễ dàng, phải không?

Sau đó, chúng tôi tạo một thể hiện của lớp

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
03 mà không chỉ định bất kỳ thuộc tính nào. Lớp nhóm tạo theo mặc định một quy trình cho mỗi lõi CPU. Tiếp theo, chúng tôi chạy phương thức
from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
07 với một vài đối số

Phương thức

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
07 áp dụng hàm
from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
09 cho mọi phần tử của iterable mà chúng tôi cung cấp — trong trường hợp này, là danh sách mọi số từ
from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
10 đến
from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
11

Ưu điểm rất lớn của điều này là các tính toán trong danh sách được thực hiện song song

Tận dụng tốt nhất Đa xử lý Python

Tạo nhiều quy trình và thực hiện tính toán song song không nhất thiết phải hiệu quả hơn tính toán nối tiếp. Đối với các tác vụ sử dụng nhiều CPU thấp, tính toán nối tiếp nhanh hơn tính toán song song. Vì lý do này, điều quan trọng là phải hiểu khi nào bạn nên sử dụng đa xử lý — điều này phụ thuộc vào các tác vụ bạn đang thực hiện

Để thuyết phục bạn về điều này, hãy xem một ví dụ đơn giản

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
0

Đoạn mã này dựa trên ví dụ trước. Chúng ta đang giải cùng một bài toán, đó là tính căn bậc hai của số

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
11, nhưng theo hai cách. Cái đầu tiên liên quan đến việc sử dụng đa xử lý Python, trong khi cái thứ hai thì không. Chúng tôi đang sử dụng phương pháp
from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
13 từ thư viện
from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
14 để đo hiệu suất thời gian

Trên máy tính xách tay của tôi, tôi nhận được kết quả này

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
1

Như bạn có thể thấy, có hơn một giây khác biệt. Vì vậy, trong trường hợp này, đa xử lý sẽ tốt hơn

Hãy thay đổi điều gì đó trong mã, chẳng hạn như giá trị của

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
11. Hãy hạ nó xuống
from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
16 và xem điều gì sẽ xảy ra

Đây là những gì tôi nhận được bây giờ

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
0

Chuyện gì đã xảy ra thế? . Tại sao?

Chi phí hoạt động được đưa ra bằng cách phân chia các tính toán giữa các quy trình là quá nhiều so với nhiệm vụ được giải quyết. Bạn có thể thấy có bao nhiêu sự khác biệt về thời gian biểu diễn

Phần kết luận

Trong bài viết này, chúng ta đã nói về việc tối ưu hóa hiệu suất của mã Python bằng cách sử dụng đa xử lý Python

Đầu tiên, chúng tôi đã giới thiệu ngắn gọn điện toán song song là gì và các mô hình chính để sử dụng nó. Sau đó, chúng tôi bắt đầu nói về đa xử lý và những ưu điểm của nó. Cuối cùng, chúng tôi thấy rằng việc tính toán song song không phải lúc nào cũng là lựa chọn tốt nhất và mô-đun

from multiprocessing import Pool
import time
import math

N = 5000000

def cube[x]:
    return math.sqrt[x]

if __name__ == "__main__":
    with Pool[] as pool:
      result = pool.map[cube, range[10,N]]
    print["Program finished!"]
1 nên được sử dụng để thực hiện song song các tác vụ liên quan đến CPU. Như mọi khi, vấn đề là xem xét vấn đề cụ thể mà bạn đang gặp phải và đánh giá ưu và nhược điểm của các giải pháp khác nhau

Tôi hy vọng bạn thấy việc tìm hiểu về đa xử lý Python hữu ích như tôi đã làm

Chia sẻ bài viết này

Lorenzo Bonanella

Tôi là một sinh viên khoa học máy tính thích đặt câu hỏi và học hỏi những điều mới. Khách du lịch, nhạc sĩ và nhà văn thỉnh thoảng. Kiểm tra tôi trên trang web của tôi

Làm thế nào đa xử lý hoạt động trong Python?

Đa xử lý Python Lớp quy trình là một phần trừu tượng thiết lập một quy trình Python khác, cung cấp cho nó khả năng chạy mã và cách để ứng dụng mẹ kiểm soát việc thực thi. There are two important functions that belongs to the Process class - start[] and join[] function.

Tôi có thể chạy bao nhiêu quy trình trong Python?

Số lượng quy trình worker tối đa có thể bị giới hạn bởi hệ điều hành của bạn . Ví dụ: trên windows, bạn sẽ không thể tạo nhiều hơn 61 tiến trình con trong chương trình Python của mình.

Python có hỗ trợ đa xử lý không?

Trong Python, đa xử lý có thể được triển khai bằng cách sử dụng mô-đun đa xử lý [hoặc đồng thời. tương lai. ProcessPoolExecutor ] có thể được sử dụng để tạo ra nhiều quy trình hệ điều hành .

Chúng ta có thể làm cho chương trình Python nhanh hơn bằng cách sử dụng nhiều quy trình không?

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

Chủ Đề