Hướng dẫn can python threads access global variable? - luồng python có thể truy cập biến toàn cục không?

Trong một chức năng:

a += 1

sẽ được trình biên dịch giải thích là assign to a => Create local variable a, đó không phải là những gì bạn muốn. Nó có thể sẽ thất bại với lỗi a not initialized vì (cục bộ) A thực sự chưa được khởi tạo:

>>> a = 1
>>> def f():
...     a += 1
... 
>>> f()
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 2, in f
UnboundLocalError: local variable 'a' referenced before assignment

Bạn có thể nhận được những gì bạn muốn với (rất cau mày và vì lý do chính đáng) global từ khóa, như vậy:

>>> def f():
...     global a
...     a += 1
... 
>>> a
1
>>> f()
>>> a
2

Tuy nhiên, nói chung, bạn nên tránh sử dụng các biến toàn cầu trở nên cực kỳ nhanh chóng. Và điều này đặc biệt đúng đối với các chương trình đa luồng, nơi bạn không có bất kỳ cơ chế đồng bộ hóa nào cho thread1 của bạn để biết khi nào a đã được sửa đổi. Nói tóm lại: Các chủ đề rất phức tạp và bạn không thể mong đợi có sự hiểu biết trực quan về thứ tự mà các sự kiện đang diễn ra khi hai (hoặc nhiều) chủ đề hoạt động trên cùng một giá trị. Ngôn ngữ, trình biên dịch, hệ điều hành, bộ xử lý ... tất cả đều có thể đóng một vai trò và quyết định sửa đổi thứ tự hoạt động cho tốc độ, tính thực tế hoặc bất kỳ lý do nào khác.complicated, and you cannot expect to have an intuitive understanding of the order in which events are happening when two (or more) threads work on the same value. The language, compiler, OS, processor... can ALL play a role, and decide to modify the order of operations for speed, practicality or any other reason.

Cách thích hợp cho loại điều này là sử dụng các công cụ chia sẻ Python (khóa và bạn bè), hoặc tốt hơn, giao tiếp dữ liệu thông qua hàng đợi thay vì chia sẻ nó, ví dụ: như thế này:

from threading import Thread
from queue import Queue
import time

def thread1(threadname, q):
    #read variable "a" modify by thread 2
    while True:
        a = q.get()
        if a is None: return # Poison pill
        print a

def thread2(threadname, q):
    a = 0
    for _ in xrange(10):
        a += 1
        q.put(a)
        time.sleep(1)
    q.put(None) # Poison pill

queue = Queue()
thread1 = Thread( target=thread1, args=("Thread-1", queue) )
thread2 = Thread( target=thread2, args=("Thread-2", queue) )

thread1.start()
thread2.start()
thread1.join()
thread2.join()

# Bảo vệ thể hiện đối tượngdata variables shared between threads using a threading.Lock mutex lock, and you can share data between threads explicitly using queue.Queue.

Trong hướng dẫn này, bạn sẽ khám phá cách chia sẻ dữ liệu giữa các luồng một cách an toàn.

Bắt đầu nào.

  • Cần chia sẻ dữ liệu giữa các luồng
  • Cách chia sẻ dữ liệu giữa các luồng
    • Chia sẻ một biến Boolean với một sự kiện
    • Truy cập dữ liệu được chia sẻ với khóa
    • Chia sẻ dữ liệu với hàng đợi
  • Cách chia sẻ các biến ở các phạm vi khác nhau
    • Chia sẻ các biến cục bộ
    • Chia sẻ các biến toàn cầu
    • Chia sẻ các biến thể hiện
  • Đọc thêm
  • Takeaways

Cần chia sẻ dữ liệu giữa các luồng

Cách chia sẻ dữ liệu giữa các luồng

Chia sẻ một biến Boolean với một sự kiện

Truy cập dữ liệu được chia sẻ với khóa

Chia sẻ dữ liệu với hàng đợithreading.Thread class.

Cách chia sẻ các biến ở các phạm vi khác nhau

  • Chia sẻ các biến cục bộ

Chia sẻ các biến toàn cầu

Chia sẻ các biến thể hiện

  • Đọc thêm
  • Takeaways
  • Một chủ đề là một chủ đề thực thi trong một chương trình máy tính.

Mỗi chương trình Python có ít nhất một luồng thực thi được gọi là luồng chính. Cả hai quy trình và luồng được tạo và quản lý bởi hệ điều hành cơ bản.

Đôi khi chúng ta có thể cần tạo các luồng bổ sung trong chương trình của chúng tôi để thực thi mã đồng thời.

Python cung cấp khả năng tạo và quản lý các luồng mới thông qua mô -đun luồng và lớp luồng.

Bạn có thể tìm hiểu thêm về các chủ đề Python trong hướng dẫn:

  • Chủ đề trong Python: Hướng dẫn hoàn chỉnh

Trong lập trình đồng thời, chúng ta có thể cần chia sẻ dữ liệu giữa các luồng.

Dữ liệu có thể đề cập đến nhiều thứ khác nhau, chẳng hạn như:

Biến toàn cầu.

Các biến cục bộ.

  • Biến thể hiện.threading.Event.
  • Nó có thể là một cái gì đó đơn giản như một bộ đếm hoặc cờ boolean, cho các cấu trúc dữ liệu và dữ liệu cụ thể của ứng dụng.threading.Lock.
  • Chúng tôi có thể cần chia sẻ dữ liệu vì nhiều lý do vì nhiều luồng cần đọc và/hoặc ghi vào cùng một biến dữ liệu.queue.Queue.

Vấn đề với nhiều luồng đọc và viết cùng một biến là nó có thể dẫn đến chế độ thất bại đồng thời được gọi là điều kiện chủng tộc.

Chia sẻ một biến Boolean với một sự kiện

Truy cập dữ liệu được chia sẻ với khóathread.Event class.

Chia sẻ dữ liệu với hàng đợi

Cách chia sẻ các biến ở các phạm vi khác nhauFalse state.

Chia sẻ các biến cục bộ..

Chia sẻ các biến toàn cầu

event=threading.Event()=threading.Event()

Chia sẻ các biến thể hiện

Đọc thêmis_set() function.

Takeaways

Chia sẻ các biến cục bộ..

Chia sẻ các biến toàn cầu

ifevent.is_set():event.is_set():

Chia sẻ các biến thể hiện

Đọc thêmTrue via the set() function and set False via the clear() function.

Takeaways

Chia sẻ các biến cục bộ..

Chia sẻ các biến toàn cầu

event.set().set()

Chia sẻ các biến thể hiện

Đọc thêm

event.clear().clear()

Takeaways

  • Một chủ đề là một chủ đề thực thi trong một chương trình máy tính.

Truy cập dữ liệu được chia sẻ với khóa

Mỗi chương trình Python có ít nhất một luồng thực thi được gọi là luồng chính. Cả hai quy trình và luồng được tạo và quản lý bởi hệ điều hành cơ bản.threading.Lock class.

Đôi khi chúng ta có thể cần tạo các luồng bổ sung trong chương trình của chúng tôi để thực thi mã đồng thời.

Python cung cấp khả năng tạo và quản lý các luồng mới thông qua mô -đun luồng và lớp luồng.

Bạn có thể tìm hiểu thêm về các chủ đề Python trong hướng dẫn:acquire() and release() functions, for example:

Chia sẻ các biến cục bộ..

Chia sẻ các biến toàn cầu

lock=threading.Lock()=threading.Lock()

Chia sẻ các biến cục bộ..

Chia sẻ các biến toàn cầu

lock.acquire().acquire()

Chia sẻ các biến thể hiện

Chia sẻ các biến cục bộ..

Chia sẻ các biến toàn cầu

lock.release().release()

Chia sẻ các biến thể hiện

Takeaways

Chia sẻ các biến cục bộ..

Chia sẻ các biến toàn cầu

lock=threading.Lock()=threading.Lock()

Chia sẻ các biến cục bộ..

Chia sẻ các biến toàn cầu

Chia sẻ các biến thể hiệnlock:

Chia sẻ các biến thể hiện

Chia sẻ các biến cục bộ..

Chia sẻ các biến toàn cầu

  • Chia sẻ các biến thể hiện

Chia sẻ dữ liệu với hàng đợi

Đọc thêmqueue.Queue class.

Takeaways

Một chủ đề là một chủ đề thực thi trong một chương trình máy tính.

  • Mỗi chương trình Python có ít nhất một luồng thực thi được gọi là luồng chính. Cả hai quy trình và luồng được tạo và quản lý bởi hệ điều hành cơ bản.: A fully-featured first-in-first-out (FIFO) queue.
  • Đôi khi chúng ta có thể cần tạo các luồng bổ sung trong chương trình của chúng tôi để thực thi mã đồng thời.: A FIFO queue with less functionality.
  • Python cung cấp khả năng tạo và quản lý các luồng mới thông qua mô -đun luồng và lớp luồng.: A last-in-first-out (LIFO) queue.
  • Bạn có thể tìm hiểu thêm về các chủ đề Python trong hướng dẫn:: A queue where the first items out are those with the highest priority.

Một hàng đợi có thể được tạo sau đó được chia sẻ giữa nhiều luồng.

.....

# Tạo một hàng đợi

queue=Queue()=Queue()

Sau khi được chia sẻ, chúng tôi có thể định cấu hình một hoặc nhiều luồng để thêm dữ liệu vào hàng đợi.

Điều này có thể đạt được thông qua hàm put (). Chúng ta có thể đặt bất kỳ đối tượng Python nào chúng ta thích trên hàng đợi.put() function. We can put any Python object we like on the queue.

Ví dụ:

.....

# Tạo một hàng đợi

foriinrange(100):iinrange(100):

Sau khi được chia sẻ, chúng tôi có thể định cấu hình một hoặc nhiều luồng để thêm dữ liệu vào hàng đợi.

queue.put(i).put(i)

Điều này có thể đạt được thông qua hàm put (). Chúng ta có thể đặt bất kỳ đối tượng Python nào chúng ta thích trên hàng đợi.

Ví dụ:get() function. Once an item of data has been retrieved from the queue, it is removed. This means that only one thread can get each item on the queue.

Ví dụ:

.....

# Loop trên dữ liệu

whileTrue:True:

# Thêm mục dữ liệu vào hàng đợi

data=queue.get()=queue.get()

Sau đó, chúng tôi có thể định cấu hình một hoặc nhiều luồng khác để đọc dữ liệu từ hàng đợi.

Điều này có thể đạt được bằng cách sử dụng hàm get (). Khi một mục dữ liệu đã được lấy từ hàng đợi, nó sẽ bị xóa. Điều này có nghĩa là chỉ một chủ đề có thể nhận được mỗi mục trên hàng đợi.

# Vòng lặp mãi mãi
Download my FREE PDF cheat sheet

# Nhận một mục dữ liệu từ hàng đợi

# ...

Ví dụ:

  • # Loop trên dữ liệu
  • # Thêm mục dữ liệu vào hàng đợi
  • Sau đó, chúng tôi có thể định cấu hình một hoặc nhiều luồng khác để đọc dữ liệu từ hàng đợi.

Điều này có thể đạt được bằng cách sử dụng hàm get (). Khi một mục dữ liệu đã được lấy từ hàng đợi, nó sẽ bị xóa. Điều này có nghĩa là chỉ một chủ đề có thể nhận được mỗi mục trên hàng đợi.

# Vòng lặp mãi mãi

# Nhận một mục dữ liệu từ hàng đợi

# ...

Bây giờ chúng ta đã biết cách chia sẻ các biến, hãy để xem xét việc chia sẻ các biến ở các phạm vi khác nhau.

Bị nhầm lẫn bởi API mô -đun luồng? Tải xuống bảng cheat pdf miễn phí của tôiqueue.Queue instance.

.....

# Tạo một hàng đợi

queue=queue.Queue()=queue.Queue()

Cách chia sẻ các biến ở các phạm vi khác nhau

Chúng ta có thể cần chia sẻ các biến được xác định ở các phạm vi khác nhau.

Các biến cục bộ trong một hàm.task_function(queue):

Sau đó, chúng tôi có thể định cấu hình một hoặc nhiều luồng khác để đọc dữ liệu từ hàng đợi.

Điều này có thể đạt được bằng cách sử dụng hàm get (). Khi một mục dữ liệu đã được lấy từ hàng đợi, nó sẽ bị xóa. Điều này có nghĩa là chỉ một chủ đề có thể nhận được mỗi mục trên hàng đợi.

.....

# Vòng lặp mãi mãi

data=55=55

# Nhận một mục dữ liệu từ hàng đợi

Ví dụ:

.....

# Loop trên dữ liệu

queue.put(data).put(data)

# Thêm mục dữ liệu vào hàng đợi

Chúng ta có thể cần chia sẻ các biến được xác định ở các phạm vi khác nhau.

Các biến cục bộ trong một hàm.task_function(queue):

# Vòng lặp mãi mãi

data=55=55

# Loop trên dữ liệu

queue.put(data).put(data)

# Thêm mục dữ liệu vào hàng đợi

Sau đó, chúng tôi có thể định cấu hình một hoặc nhiều luồng khác để đọc dữ liệu từ hàng đợi.

Điều này có thể đạt được bằng cách sử dụng hàm get (). Khi một mục dữ liệu đã được lấy từ hàng đợi, nó sẽ bị xóa. Điều này có nghĩa là chỉ một chủ đề có thể nhận được mỗi mục trên hàng đợi.another_task_function(queue):

Sau đó, chúng tôi có thể định cấu hình một hoặc nhiều luồng khác để đọc dữ liệu từ hàng đợi.

Điều này có thể đạt được bằng cách sử dụng hàm get (). Khi một mục dữ liệu đã được lấy từ hàng đợi, nó sẽ bị xóa. Điều này có nghĩa là chỉ một chủ đề có thể nhận được mỗi mục trên hàng đợi.

Ví dụ:

.....

# Vòng lặp mãi mãi

data=queue.get()=queue.get()

# Nhận một mục dữ liệu từ hàng đợi

Sau đó, chúng tôi có thể định cấu hình một hoặc nhiều luồng khác để đọc dữ liệu từ hàng đợi.

Điều này có thể đạt được bằng cách sử dụng hàm get (). Khi một mục dữ liệu đã được lấy từ hàng đợi, nó sẽ bị xóa. Điều này có nghĩa là chỉ một chủ đề có thể nhận được mỗi mục trên hàng đợi.another_task_function(queue):

# Vòng lặp mãi mãi

data=queue.get()=queue.get()

# Nhận một mục dữ liệu từ hàng đợi

# ...

Bây giờ chúng ta đã biết cách chia sẻ các biến, hãy để xem xét việc chia sẻ các biến ở các phạm vi khác nhau.

Ví dụ:

.....

Bị nhầm lẫn bởi API mô -đun luồng? Tải xuống bảng cheat pdf miễn phí của tôi

data=66=66

Cách chia sẻ các biến ở các phạm vi khác nhau

Ví dụ:

Chúng ta có thể cần chia sẻ các biến được xác định ở các phạm vi khác nhau.

Các biến cục bộ trong một hàm.custom():

Các biến toàn cầu được xác định trong một kịch bản.

data=33=33

Các biến thể hiện được xác định trong một lớp.

Ví dụ:

Chúng ta có thể cần chia sẻ các biến được xác định ở các phạm vi khác nhau.

Các biến cục bộ trong một hàm.custom():

Các biến toàn cầu được xác định trong một kịch bản.

Các biến thể hiện được xác định trong một lớp.data

Các biến toàn cầu được xác định trong một kịch bản.

data=33=33

Các biến thể hiện được xác định trong một lớp.

Hãy cùng nhau xem lần lượt xem.threading.Lock class.

Chia sẻ các biến cục bộ

Ví dụ:

.....

Bị nhầm lẫn bởi API mô -đun luồng? Tải xuống bảng cheat pdf miễn phí của tôi

data=66=66

Cách chia sẻ các biến ở các phạm vi khác nhau

lock=threading.Lock()=threading.Lock()

Chúng ta có thể cần chia sẻ các biến được xác định ở các phạm vi khác nhau.

Các biến cục bộ trong một hàm.

Ví dụ:

Chúng ta có thể cần chia sẻ các biến được xác định ở các phạm vi khác nhau.

Các biến cục bộ trong một hàm.custom():

Các biến toàn cầu được xác định trong một kịch bản.

Các biến thể hiện được xác định trong một lớp.lock:

Các biến toàn cầu được xác định trong một kịch bản.

data=33=33

Các biến thể hiện được xác định trong một lớp.

Hãy cùng nhau xem lần lượt xem.

Chia sẻ các biến cục bộ

Một biến được xác định trong một hàm được gọi là biến cục bộ.

classCustomClass():CustomClass():

Chúng tôi có thể chia sẻ một biến cục bộ giữa các luồng bằng cách sử dụng hàng đợi.

Hàng đợi phải được chia sẻ và truy cập vào từng luồng và trong hàm nơi biến cục bộ được xác định và sử dụng.__init__(self):

Ví dụ: trước tiên chúng ta có thể tạo một thể hiện hàng đợi.

self.data=33.data=33

Sau đó, chúng ta có thể chuyển hàng đợi đến chức năng của chúng ta như một đối số.

Ví dụ:

# chức năng tác vụ tùy chỉnh được thực hiện bởi một luồng

Def Task_Function (Hàng đợi):task(self):

self.data=22.data=22

Toàn bộ lớp có thể trông như sau:

# Lớp tùy chỉnh

classCustomClass():CustomClass():

# người xây dựng

def __init __ (tự):__init__(self):

# Xác định một biến thể hiện

self.data=33.data=33

# Phương thức trên lớp

nhiệm vụ def (tự):task(self):

self.data=22.data=22

Chúng tôi có thể tạo một thể hiện của lớp và nhiều luồng có thể truy cập lớp, chẳng hạn như gọi các phương thức trên lớp truy cập hoặc sửa đổi biến thể hiện.

.....

# Tạo một thể hiện

custom=CustomClass()=CustomClass()

custom.task().task()

Mỗi luồng truy cập các phương thức trên đối tượng được chia sẻ có thể sửa đổi biến thể hiện, dẫn đến các điều kiện chủng tộc.

Một cách để ngăn chặn một cuộc đua với các biến thể hiện trong phiên bản đối tượng là đảm bảo rằng tất cả các quyền truy cập vào đối tượng được chia sẻ được bảo vệ bởi khóa mutex.

Ví dụ:

.....

# Tạo một thể hiện

custom=CustomClass()=CustomClass()

Mỗi luồng truy cập các phương thức trên đối tượng được chia sẻ có thể sửa đổi biến thể hiện, dẫn đến các điều kiện chủng tộc.

lock=threading.Lock()=threading.Lock()

.....

# Tạo một thể hiện

Mỗi luồng truy cập các phương thức trên đối tượng được chia sẻ có thể sửa đổi biến thể hiện, dẫn đến các điều kiện chủng tộc.lock:

Một cách để ngăn chặn một cuộc đua với các biến thể hiện trong phiên bản đối tượng là đảm bảo rằng tất cả các quyền truy cập vào đối tượng được chia sẻ được bảo vệ bởi khóa mutex.

custom.task().task()

Ví dụ:

# Tạo khóa để bảo vệ thể hiện

Ví dụ:

# người xây dựng

def __init __ (tự):__init__(self):

# Xác định một biến thể hiện

self.data=33.data=33

# Phương thức trên lớp

self.lock=threading.Lock().lock =threading.Lock()

nhiệm vụ def (tự):

# Phương thức trên lớp

nhiệm vụ def (tự):task(self):

Chúng tôi có thể tạo một thể hiện của lớp và nhiều luồng có thể truy cập lớp, chẳng hạn như gọi các phương thức trên lớp truy cập hoặc sửa đổi biến thể hiện.

...self.lock:

# Tạo một thể hiện

self.data=22.data=22

Mỗi luồng truy cập các phương thức trên đối tượng được chia sẻ có thể sửa đổi biến thể hiện, dẫn đến các điều kiện chủng tộc.

Một cách để ngăn chặn một cuộc đua với các biến thể hiện trong phiên bản đối tượng là đảm bảo rằng tất cả các quyền truy cập vào đối tượng được chia sẻ được bảo vệ bởi khóa mutex.


Ví dụ:

# Tạo khóa để bảo vệ thể hiện

# Bảo vệ thể hiện đối tượng

với khóa:
 


# Tương tác với đối tượng chia sẻ

Một cách tiếp cận khác là bảo vệ biến thể hiện trong chính lớp.

  • Điều này có thể đạt được bằng cách xác định khóa là biến trường hợp thứ hai trong lớp, chẳng hạn như trong trình xây dựng lớp.
  • # Xác định khóa để bảo vệ biến thể hiện
  • Sau đó, trong các phương thức tương tác với biến thể hiện, chúng ta có thể bảo vệ biến với khóa.
  • # có được khóa
  • với self.lock:

# Sửa đổi biến thể hiện

Điều này gói gọn các biện pháp an toàn luồng cho biến thể hiện trong lớp.

Các luồng sau đó có thể gọi các chức năng trên lớp và biết rằng trạng thái bên trong của lớp được bảo vệ. Nhận xét về lớp học sẽ cần phải tuyên bố rằng lớp an toàn cho luồng và những phương thức cố gắng có được khóa sẽ cần phải tuyên bố rằng chúng có thể chặn.
Ask your questions in the comments below and I will do my best to answer.

Khóa học luồng python miễn phí