Khóa liên tiến trình python

mô-đun đa xử lý trong python cung cấp giao diện gọn gàng để bảo vệ tài nguyên dùng chung [tệp, biến] khỏi bị sửa đổi bởi hai hoặc nhiều quy trình đang chạy đồng thời

Chúng tôi sẽ sử dụng ví dụ về giao dịch ngân hàng dễ hiểu để minh họa tác động của việc không sử dụng khóa để bảo vệ tài nguyên được chia sẻ, trong trường hợp này là tài khoản và sau đó áp dụng khóa để kích hoạt bảo vệ

Không có khóa được sử dụng

Bộ nhớ dùng chung được tạo bằng cách sử dụng đối tượng Giá trị được cung cấp bởi mô-đun đa xử lý mà chúng tôi đặt tên là số dư. Giá trị ban đầu được đặt thành 500$. Có hai chức năng rút tiền và gửi tiền lần lượt trừ và thêm 500 đô la. Sau đó, hai quy trình được bắt đầu với khoản tiền gửi bắt đầu trước. Chúng tôi dự kiến ​​số dư cuối cùng sẽ không thay đổi và vẫn là 500 đô la nhưng khi bạn chạy chương trình nhiều lần, bạn sẽ nhận thấy số dư cuối cùng ở khắp mọi nơi. Trên hệ thống của tôi, tôi nhận được 493, 514, 500. Lý do cho điều này là trong khi khoản tiền gửi đang trong quá trình cập nhật số dư chưa được phản ánh trong bộ nhớ thực, thì chức năng rút tiền sẽ sử dụng giá trị số dư cũ hơn và khấu trừ từ đó thay vào đó. Sự không thể đoán trước về giá trị của sự cân bằng này chẳng qua là một điều kiện chạy đua

Chúng ta có thể thấy rằng vấn đề nằm ở dòng

balance = balance.value + 1 [from deposit function]
balance = balance.value - 1 [from withdraw function]

đây là phần được gọi là phần quan trọng của mã và phải được bảo vệ bởi một số cơ chế. Hãy xem cách sử dụng khóa để làm điều đó

có khóa

Cả hai chức năng hiện được sửa đổi để sử dụng khóa đối số bổ sung. Bây giờ bạn có thể thấy phần quan trọng đang được khóa bảo vệ. thu được [] và khóa. cơ chế phát hành [] đảm bảo quy trình khác không thể truy cập vào số dư tài nguyên được chia sẻ khi nó được sử dụng và phải đợi nó được giải phóng. Nếu bạn chạy chương trình này nhiều lần bây giờ, bạn sẽ luôn nhận được 500 đô la làm số dư cuối cùng

Điểm rút ra từ hướng dẫn ngắn này là nếu chương trình của bạn đang sử dụng một số dạng đồng thời [đa luồng hoặc đa xử lý], hãy xác định các phần quan trọng trong mã của bạn và bảo vệ chúng bằng cách sử dụng khóa.

Mỗi chương trình Python được thực thi trong một Quy trình, đây là phiên bản mới của trình thông dịch Python. Quá trình này có tên MainProcess và có một luồng được sử dụng để thực hiện các hướng dẫn của chương trình được gọi là MainThread. Cả quy trình và luồng đều được tạo và quản lý bởi hệ điều hành bên dưới

Đôi khi chúng ta có thể cần tạo các tiến trình con mới trong chương trình của mình để thực thi mã đồng thời

Python cung cấp khả năng tạo và quản lý các quy trình mới thông qua

Bạn có thể tìm hiểu thêm về đa xử lý trong hướng dẫn

  • Đa xử lý trong Python. Hướng dẫn hoàn chỉnh

Khi viết các chương trình đồng thời, chúng tôi có thể cần chia sẻ dữ liệu hoặc tài nguyên giữa các quy trình, thường phải được bảo vệ bằng khóa loại trừ lẫn nhau

Cơ chế được sử dụng phổ biến nhất để đảm bảo loại trừ lẫn nhau là khóa loại trừ lẫn nhau hoặc mutex hoặc đơn giản là khóa. Mutex là một loại đối tượng đặc biệt có hỗ trợ trong phần cứng cơ bản. Ý tưởng cơ bản là mỗi phần quan trọng được bảo vệ bằng khóa

— Trang 53, Giới thiệu về lập trình song song, 2020

Bạn có thể tìm hiểu thêm về khóa mutex trong hướng dẫn

  • Cách sử dụng Khóa Mutex trong Python

Làm cách nào chúng ta có thể sử dụng khóa mutex với các quy trình trong Python?

Chạy các vòng lặp của bạn bằng cách sử dụng tất cả các CPU, tải xuống cuốn sách MIỄN PHÍ của tôi để tìm hiểu cách thực hiện

Cách sử dụng Khóa Mutex

Khóa loại trừ lẫn nhau hoặc khóa mutex là nguyên tắc đồng bộ hóa nhằm ngăn chặn tình trạng dồn đuổi

Bạn có thể tìm hiểu thêm về điều kiện chạy đua giữa các quy trình trong hướng dẫn

  • Điều kiện cuộc đua đa xử lý trong Python

Python cung cấp khóa loại trừ lẫn nhau để sử dụng với các quy trình thông qua đa xử lý. khóa lớp

Một phiên bản của khóa có thể được tạo và sau đó được các quy trình thu thập trước khi truy cập phần quan trọng và được giải phóng sau phần quan trọng

Ví dụ

1

2

3

4

5

6

7

8

.. .

# tạo khóa

khóa = đa xử lý. Khóa[]

# lấy khóa

khóa. có được[]

#

# nhả khóa

khóa. phát hành[]

Chỉ có một quá trình có thể có khóa bất cứ lúc nào. Nếu một quá trình không giải phóng một khóa đã lấy, thì nó không thể được lấy lại

Quá trình cố gắng lấy khóa sẽ bị chặn cho đến khi có được khóa, chẳng hạn như nếu một quá trình khác hiện đang giữ khóa thì sẽ giải phóng nó

Chúng tôi có thể cố gắng lấy khóa mà không chặn bằng cách đặt đối số "chặn" thành Sai. Nếu không lấy được khóa, giá trị Sai được trả về

1

2

3

.. .

# có được khóa mà không cần chặn

khóa. có được[chặn=false]

Chúng tôi cũng có thể cố gắng lấy khóa khi hết thời gian chờ, điều này sẽ đợi số giây đã đặt để lấy khóa trước khi từ bỏ. Nếu không lấy được khóa, giá trị Sai được trả về

1

2

3

.. .

# có được khóa với thời gian chờ

khóa. mua lại[thời gian chờ=10]

Chúng ta cũng có thể sử dụng khóa thông qua giao thức quản lý bối cảnh thông qua câu lệnh with, cho phép phần quan trọng trở thành một khối trong quá trình sử dụng khóa và khóa sẽ tự động được giải phóng sau khi khối hoàn thành

Ví dụ

1

2

3

4

5

6

.. .

# tạo khóa

khóa = đa xử lý. Khóa[]

# lấy khóa

với khóa.

    #.

Đây là cách sử dụng ưa thích vì nó làm rõ nơi mã được bảo vệ bắt đầu và kết thúc, đồng thời đảm bảo rằng khóa luôn được giải phóng, ngay cả khi có ngoại lệ hoặc lỗi trong phần quan trọng

Chúng tôi cũng có thể kiểm tra xem khóa hiện có được lấy bởi một quy trình thông qua chức năng bị khóa []

1

2

3

4

.. .

# kiểm tra xem khóa có được mua hay không

nếu khóa. bị khóa[].

    #.

Python cũng cung cấp một khóa mutex để sử dụng với các luồng. Bạn có thể tìm hiểu thêm về nó trong hướng dẫn này

  • Cách sử dụng Khóa Mutex trong Python

Bây giờ chúng ta đã biết cách sử dụng đa xử lý. Lock, hãy xem một ví dụ đã hoạt động

Bị bối rối bởi API mô-đun đa xử lý?
Tải xuống bảng cheat PDF MIỄN PHÍ của tôi

Ví dụ về việc sử dụng Khóa đa xử lý

Chúng tôi có thể phát triển một ví dụ để minh họa cách sử dụng khóa mutex

Đầu tiên, chúng ta có thể định nghĩa một hàm tác vụ đích lấy khóa làm đối số và sử dụng khóa để bảo vệ phần quan trọng

Trong trường hợp này, phần quan trọng liên quan đến việc báo cáo một tin nhắn và chặn trong một phần giây

1

2

3

4

5

6

# chức năng làm việc

def nhiệm vụ[khóa, identifier, value]:

    # giành được khóa

    với khóa.

        in[f'>xử lý {identifier}]

        ngủ[giá trị]

Tiếp theo, chúng ta có thể tạo một thể hiện của đa xử lý. Khóa được chia sẻ giữa các quy trình

1

2

3

.. .

# tạo khóa chung

khóa = Khóa[]

Sau đó, chúng tôi có thể tạo nhiều quy trình, mỗi quy trình được định cấu hình để thực thi hàm task[] của chúng tôi và cạnh tranh để thực thi phần quan trọng

Mỗi quá trình sẽ nhận được khóa chia sẻ làm đối số cũng như id số nguyên từ 0 đến 9 và thời gian ngẫu nhiên để ngủ tính bằng giây từ 0 đến 1

Chúng tôi có thể thực hiện điều này thông qua việc hiểu danh sách, tạo danh sách mười bộ đa xử lý được định cấu hình. trường hợp xử lý

1

2

3

.. .

# tạo một số quy trình với thời gian ngủ khác nhau

quy trình = [Quy trình[target=task, args=[lock, i, random[]]] for i in range[10]]

Tiếp theo, chúng ta có thể bắt đầu tất cả các quy trình

1

2

3

4

.. .

# bắt đầu các quy trình

cho quy trình trong quy trình.

    quy trình. bắt đầu[]

Cuối cùng, chúng ta có thể đợi tất cả các tiến trình con mới kết thúc

1

2

3

4

.. .

# chờ cho tất cả các quá trình kết thúc

cho quy trình trong quy trình.

    quy trình. tham gia[]

Liên kết điều này lại với nhau, ví dụ hoàn chỉnh về việc sử dụng khóa được liệt kê bên dưới

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#Trăn Siêu Nhanh. com

# ví dụ về khóa loại trừ lẫn nhau [mutex] cho các quy trình

từ thời gian nhập ngủ

từ ngẫu nhiên nhập ngẫu nhiên

từ đa xử lý nhập Quy trình

từ đa xử lý nhập Khóa

 

# chức năng làm việc

def nhiệm vụ[khóa, identifier, value]:

    # giành được khóa

    với khóa.

        in[f'>xử lý {identifier}]

        ngủ[giá trị]

 

# điểm vào

if __name__ == '__main__'.

   # tạo khóa chung

    khóa = Khóa[]

   # tạo một số quy trình có thời gian ngủ khác nhau

    quy trình = [Quy trình[target=task, args=[lock, i, random[]]] for i in range[10]]

    # bắt đầu quy trình

    cho quy trình trong quy trình:

        quy trình. bắt đầu[]

   # đợi tất cả quá trình hoàn tất

    cho quy trình trong quy trình:

        quy trình. tham gia[]

Chạy ví dụ sẽ bắt đầu mười quy trình được định cấu hình để thực thi chức năng tùy chỉnh của chúng tôi

Các tiến trình con sau đó được bắt đầu và tiến trình chính chặn cho đến khi tất cả các tiến trình con kết thúc

Mỗi tiến trình con cố gắng lấy khóa trong hàm task[]. Chỉ một quá trình có thể lấy khóa tại một thời điểm và sau khi thực hiện, chúng sẽ báo cáo một thông báo bao gồm id của chúng và thời gian chúng sẽ ngủ. Sau đó, quá trình này sẽ chặn trong một phần giây trước khi nhả khóa

Kết quả cụ thể của bạn có thể thay đổi do sử dụng các số ngẫu nhiên. Hãy thử chạy ví dụ một vài lần

1

2

3

4

5

6

7

8

9

10

> quá trình 2 có khóa, ngủ trong 0. 34493199862842716

> quá trình 0 có khóa, ngủ trong 0. 1690829274493061

> quá trình 1 có khóa, ngủ trong 0. 586700038562483

> quá trình 3 có khóa, ngủ trong 0. 8439760508777033

> quá trình 4 có khóa, ngủ trong 0. 49642440261633747

> quá trình 6 có khóa, ngủ trong 0. 7291278047802177

> quá trình 5 có khóa, ngủ trong 0. 4495745681185115

> quá trình 7 có khóa, ngủ trong 0. 6844618818829677

> quá trình 8 có khóa, ngủ trong 0. 21518155457911792

> quá trình 9 có khóa, ngủ trong 0. 30577395898093285

Khóa học đa xử lý Python miễn phí

Tải xuống bảng cheat API đa xử lý của tôi và như một phần thưởng, bạn sẽ nhận được quyền truy cập MIỄN PHÍ vào khóa học email 7 ngày của tôi

Khám phá cách sử dụng mô-đun đa xử lý Python, bao gồm cách tạo và bắt đầu các tiến trình con cũng như cách sử dụng khóa mutex và semaphores

Chủ Đề