Danh sách python loại bỏ chủ đề an toàn

Gọi

from threading import Thread
import time

# all threads can access this global variable
database_value = 0

def increase():
    global database_value # needed to modify the global value

    # get a local copy (simulate data retrieving)
    local_copy = database_value

    # simulate some modifying operation
    local_copy += 1
    time.sleep(0.1)

    # write the calculated new value into the global variable
    database_value = local_copy


if __name__ == "__main__":

    print('Start value: ', database_value)

    t1 = Thread(target=increase)
    t2 = Thread(target=increase)

    t1.start()
    t2.start()

    t1.join()
    t2.join()

    print('End value:', database_value)

    print('end main')
7 để nói với chương trình rằng nó nên đợi chuỗi này hoàn thành trước khi tiếp tục với phần còn lại của mã

Show

from threading import Thread

def square_numbers():
    for i in range(1000):
        result = i * i


if __name__ == "__main__":        
    threads = []
    num_threads = 10

    # create threads and asign a function for each thread
    for i in range(num_threads):
        thread = Thread(target=square_numbers)
        threads.append(thread)

    # start all threads
    for thread in threads:
        thread.start()

    # wait for all threads to finish
    # block the main thread until these threads are finished
    for thread in threads:
        thread.join()

Chia sẻ dữ liệu giữa các luồng

Vì các luồng nằm trong cùng một không gian bộ nhớ nên chúng có quyền truy cập vào cùng một dữ liệu (công khai). Vì vậy, ví dụ, bạn có thể chỉ cần sử dụng một biến toàn cục mà tất cả các luồng có quyền truy cập đọc và ghi

Nhiệm vụ. Tạo hai luồng, mỗi luồng sẽ truy cập giá trị cơ sở dữ liệu hiện tại, sửa đổi nó (trong trường hợp này chỉ tăng giá trị đó lên 1) và ghi lại giá trị mới vào giá trị cơ sở dữ liệu. Mỗi luồng nên thực hiện thao tác này 10 lần

from threading import Thread
import time

# all threads can access this global variable
database_value = 0

def increase():
    global database_value # needed to modify the global value

    # get a local copy (simulate data retrieving)
    local_copy = database_value

    # simulate some modifying operation
    local_copy += 1
    time.sleep(0.1)

    # write the calculated new value into the global variable
    database_value = local_copy


if __name__ == "__main__":

    print('Start value: ', database_value)

    t1 = Thread(target=increase)
    t2 = Thread(target=increase)

    t1.start()
    t2.start()

    t1.join()
    t2.join()

    print('End value:', database_value)

    print('end main')

Start value:  0
End value: 1
end main

Cách sử dụng from threading import Thread import time # all threads can access this global variable database_value = 0 def increase(): global database_value # needed to modify the global value # get a local copy (simulate data retrieving) local_copy = database_value # simulate some modifying operation local_copy += 1 time.sleep(0.1) # write the calculated new value into the global variable database_value = local_copy if __name__ == "__main__": print('Start value: ', database_value) t1 = Thread(target=increase) t2 = Thread(target=increase) t1.start() t2.start() t1.join() t2.join() print('End value:', database_value) print('end main') 1

Lưu ý rằng trong ví dụ trên, 2 luồng sẽ tăng giá trị lên 1, vì vậy 2 thao tác tăng được thực hiện. Nhưng tại sao giá trị cuối cùng là 1 chứ không phải 2?

Điều kiện của cuộc đua

Một điều kiện cuộc đua đã xảy ra ở đây. Tình trạng dồn đuổi xảy ra khi hai hoặc nhiều luồng có thể truy cập dữ liệu được chia sẻ và chúng cố gắng thay đổi dữ liệu đó cùng một lúc. Vì thuật toán lập lịch luồng có thể hoán đổi giữa các luồng bất kỳ lúc nào, nên bạn không biết thứ tự các luồng sẽ cố gắng truy cập dữ liệu được chia sẻ. Trong trường hợp của chúng tôi, chuỗi đầu tiên truy cập vào

from threading import Thread
import time

# all threads can access this global variable
database_value = 0

def increase():
    global database_value # needed to modify the global value

    # get a local copy (simulate data retrieving)
    local_copy = database_value

    # simulate some modifying operation
    local_copy += 1
    time.sleep(0.1)

    # write the calculated new value into the global variable
    database_value = local_copy


if __name__ == "__main__":

    print('Start value: ', database_value)

    t1 = Thread(target=increase)
    t2 = Thread(target=increase)

    t1.start()
    t2.start()

    t1.join()
    t2.join()

    print('End value:', database_value)

    print('end main')
9 (0) và lưu trữ nó trong một bản sao cục bộ. Sau đó, nó tăng lên (
Start value:  0
End value: 1
end main
0 bây giờ là 1). Với chức năng
Start value:  0
End value: 1
end main
1 của chúng tôi chỉ mô phỏng một số thao tác tốn thời gian, chương trình sẽ chuyển sang chuỗi thứ hai trong thời gian chờ đợi. Điều này cũng sẽ truy xuất
from threading import Thread
import time

# all threads can access this global variable
database_value = 0

def increase():
    global database_value # needed to modify the global value

    # get a local copy (simulate data retrieving)
    local_copy = database_value

    # simulate some modifying operation
    local_copy += 1
    time.sleep(0.1)

    # write the calculated new value into the global variable
    database_value = local_copy


if __name__ == "__main__":

    print('Start value: ', database_value)

    t1 = Thread(target=increase)
    t2 = Thread(target=increase)

    t1.start()
    t2.start()

    t1.join()
    t2.join()

    print('End value:', database_value)

    print('end main')
9 hiện tại (vẫn là 0) và tăng
Start value:  0
End value: 1
end main
0 lên 1. Bây giờ cả hai chủ đề đều có một bản sao cục bộ với giá trị 1, vì vậy cả hai sẽ ghi 1 vào
from threading import Thread
import time

# all threads can access this global variable
database_value = 0

def increase():
    global database_value # needed to modify the global value

    # get a local copy (simulate data retrieving)
    local_copy = database_value

    # simulate some modifying operation
    local_copy += 1
    time.sleep(0.1)

    # write the calculated new value into the global variable
    database_value = local_copy


if __name__ == "__main__":

    print('Start value: ', database_value)

    t1 = Thread(target=increase)
    t2 = Thread(target=increase)

    t1.start()
    t2.start()

    t1.join()
    t2.join()

    print('End value:', database_value)

    print('end main')
9 toàn cầu. Đây là lý do tại sao giá trị cuối cùng là 1 chứ không phải 2

Tránh các điều kiện cuộc đua với from threading import Thread import time # all threads can access this global variable database_value = 0 def increase(): global database_value # needed to modify the global value # get a local copy (simulate data retrieving) local_copy = database_value # simulate some modifying operation local_copy += 1 time.sleep(0.1) # write the calculated new value into the global variable database_value = local_copy if __name__ == "__main__": print('Start value: ', database_value) t1 = Thread(target=increase) t2 = Thread(target=increase) t1.start() t2.start() t1.join() t2.join() print('End value:', database_value) print('end main') 1

Khóa (còn được gọi là mutex) là một cơ chế đồng bộ hóa để thực thi các giới hạn đối với quyền truy cập vào tài nguyên trong môi trường có nhiều luồng thực thi. Khóa có hai trạng thái. bị khóa và mở khóa. Nếu trạng thái bị khóa, nó không cho phép các luồng khác đồng thời vào phần mã này cho đến khi trạng thái được mở khóa trở lại

Hai chức năng quan trọng. -

Start value:  0
End value: 1
end main
6. Điều này sẽ khóa trạng thái và chặn -
Start value:  0
End value: 1
end main
7. Điều này sẽ mở khóa trạng thái một lần nữa

Quan trọng. Bạn phải luôn giải phóng lại khối sau khi có được nó

Trong ví dụ của chúng tôi, phần mã quan trọng nơi các giá trị cơ sở dữ liệu được truy xuất và sửa đổi hiện đã bị khóa. Điều này ngăn luồng thứ hai sửa đổi dữ liệu chung cùng một lúc. Không có nhiều thay đổi trong mã của chúng tôi. Tất cả các thay đổi mới được nhận xét trong mã bên dưới

from threading import Thread

def square_numbers():
    for i in range(1000):
        result = i * i


if __name__ == "__main__":        
    threads = []
    num_threads = 10

    # create threads and asign a function for each thread
    for i in range(num_threads):
        thread = Thread(target=square_numbers)
        threads.append(thread)

    # start all threads
    for thread in threads:
        thread.start()

    # wait for all threads to finish
    # block the main thread until these threads are finished
    for thread in threads:
        thread.join()
4

from threading import Thread

def square_numbers():
    for i in range(1000):
        result = i * i


if __name__ == "__main__":        
    threads = []
    num_threads = 10

    # create threads and asign a function for each thread
    for i in range(num_threads):
        thread = Thread(target=square_numbers)
        threads.append(thread)

    # start all threads
    for thread in threads:
        thread.start()

    # wait for all threads to finish
    # block the main thread until these threads are finished
    for thread in threads:
        thread.join()
5

Sử dụng khóa làm trình quản lý ngữ cảnh

Sau

Start value:  0
End value: 1
end main
6, bạn đừng bao giờ quên gọi cho
Start value:  0
End value: 1
end main
7 để mở khóa mã. Bạn cũng có thể sử dụng khóa làm trình quản lý bối cảnh, khóa này sẽ khóa và mở khóa mã của bạn một cách an toàn. Nên sử dụng khóa theo cách này

from threading import Thread

def square_numbers():
    for i in range(1000):
        result = i * i


if __name__ == "__main__":        
    threads = []
    num_threads = 10

    # create threads and asign a function for each thread
    for i in range(num_threads):
        thread = Thread(target=square_numbers)
        threads.append(thread)

    # start all threads
    for thread in threads:
        thread.start()

    # wait for all threads to finish
    # block the main thread until these threads are finished
    for thread in threads:
        thread.join()
8

Sử dụng hàng đợi trong Python

Hàng đợi có thể được sử dụng để trao đổi dữ liệu an toàn luồng/an toàn quy trình và xử lý dữ liệu cả trong môi trường đa luồng và đa xử lý

hàng đợi

Hàng đợi là một cấu trúc dữ liệu tuyến tính tuân theo nguyên tắc Nhập trước xuất trước (FIFO). Một ví dụ điển hình là một hàng khách đang xếp hàng chờ đợi, trong đó khách hàng đến trước được phục vụ trước.

from threading import Thread

def square_numbers():
    for i in range(1000):
        result = i * i


if __name__ == "__main__":        
    threads = []
    num_threads = 10

    # create threads and asign a function for each thread
    for i in range(num_threads):
        thread = Thread(target=square_numbers)
        threads.append(thread)

    # start all threads
    for thread in threads:
        thread.start()

    # wait for all threads to finish
    # block the main thread until these threads are finished
    for thread in threads:
        thread.join()
9

from threading import Thread
import time

# all threads can access this global variable
database_value = 0

def increase():
    global database_value # needed to modify the global value

    # get a local copy (simulate data retrieving)
    local_copy = database_value

    # simulate some modifying operation
    local_copy += 1
    time.sleep(0.1)

    # write the calculated new value into the global variable
    database_value = local_copy


if __name__ == "__main__":

    print('Start value: ', database_value)

    t1 = Thread(target=increase)
    t2 = Thread(target=increase)

    t1.start()
    t2.start()

    t1.join()
    t2.join()

    print('End value:', database_value)

    print('end main')
0

Sử dụng hàng đợi trong đa luồng

Các hoạt động với một hàng đợi là luồng an toàn. Các phương pháp quan trọng là

  • from threading import Thread
    
    def square_numbers():
        for i in range(1000):
            result = i * i
    
    
    if __name__ == "__main__":        
        threads = []
        num_threads = 10
    
        # create threads and asign a function for each thread
        for i in range(num_threads):
            thread = Thread(target=square_numbers)
            threads.append(thread)
    
        # start all threads
        for thread in threads:
            thread.start()
    
        # wait for all threads to finish
        # block the main thread until these threads are finished
        for thread in threads:
            thread.join()
    
    40. Xóa và trả lại mục đầu tiên. Theo mặc định, nó chặn cho đến khi có mặt hàng
  • from threading import Thread
    
    def square_numbers():
        for i in range(1000):
            result = i * i
    
    
    if __name__ == "__main__":        
        threads = []
        num_threads = 10
    
        # create threads and asign a function for each thread
        for i in range(num_threads):
            thread = Thread(target=square_numbers)
            threads.append(thread)
    
        # start all threads
        for thread in threads:
            thread.start()
    
        # wait for all threads to finish
        # block the main thread until these threads are finished
        for thread in threads:
            thread.join()
    
    41. Đặt phần tử ở cuối hàng đợi. Theo mặc định, nó sẽ chặn cho đến khi có một vị trí miễn phí
  • from threading import Thread
    
    def square_numbers():
        for i in range(1000):
            result = i * i
    
    
    if __name__ == "__main__":        
        threads = []
        num_threads = 10
    
        # create threads and asign a function for each thread
        for i in range(num_threads):
            thread = Thread(target=square_numbers)
            threads.append(thread)
    
        # start all threads
        for thread in threads:
            thread.start()
    
        # wait for all threads to finish
        # block the main thread until these threads are finished
        for thread in threads:
            thread.join()
    
    42. Chỉ ra rằng một nhiệm vụ được xử lý trước đây đã hoàn thành. Đối với mỗi
    from threading import Thread
    
    def square_numbers():
        for i in range(1000):
            result = i * i
    
    
    if __name__ == "__main__":        
        threads = []
        num_threads = 10
    
        # create threads and asign a function for each thread
        for i in range(num_threads):
            thread = Thread(target=square_numbers)
            threads.append(thread)
    
        # start all threads
        for thread in threads:
            thread.start()
    
        # wait for all threads to finish
        # block the main thread until these threads are finished
        for thread in threads:
            thread.join()
    
    43, bạn nên gọi nó sau khi bạn hoàn thành nhiệm vụ của mình cho mục này
  • from threading import Thread
    
    def square_numbers():
        for i in range(1000):
            result = i * i
    
    
    if __name__ == "__main__":        
        threads = []
        num_threads = 10
    
        # create threads and asign a function for each thread
        for i in range(num_threads):
            thread = Thread(target=square_numbers)
            threads.append(thread)
    
        # start all threads
        for thread in threads:
            thread.start()
    
        # wait for all threads to finish
        # block the main thread until these threads are finished
        for thread in threads:
            thread.join()
    
    44. Chặn cho đến khi tất cả các mục trong hàng đợi đã được nhận và xử lý (
    from threading import Thread
    
    def square_numbers():
        for i in range(1000):
            result = i * i
    
    
    if __name__ == "__main__":        
        threads = []
        num_threads = 10
    
        # create threads and asign a function for each thread
        for i in range(num_threads):
            thread = Thread(target=square_numbers)
            threads.append(thread)
    
        # start all threads
        for thread in threads:
            thread.start()
    
        # wait for all threads to finish
        # block the main thread until these threads are finished
        for thread in threads:
            thread.join()
    
    45 đã được gọi cho mỗi mục)
  • from threading import Thread
    
    def square_numbers():
        for i in range(1000):
            result = i * i
    
    
    if __name__ == "__main__":        
        threads = []
        num_threads = 10
    
        # create threads and asign a function for each thread
        for i in range(num_threads):
            thread = Thread(target=square_numbers)
            threads.append(thread)
    
        # start all threads
        for thread in threads:
            thread.start()
    
        # wait for all threads to finish
        # block the main thread until these threads are finished
        for thread in threads:
            thread.join()
    
    46. Trả về True nếu hàng đợi rỗng

Ví dụ sau sử dụng hàng đợi để trao đổi số từ 0. 19. Mỗi luồng gọi phương thức

from threading import Thread

def square_numbers():
    for i in range(1000):
        result = i * i


if __name__ == "__main__":        
    threads = []
    num_threads = 10

    # create threads and asign a function for each thread
    for i in range(num_threads):
        thread = Thread(target=square_numbers)
        threads.append(thread)

    # start all threads
    for thread in threads:
        thread.start()

    # wait for all threads to finish
    # block the main thread until these threads are finished
    for thread in threads:
        thread.join()
47. Bên trong vòng lặp vô hạn, luồng đang đợi cho đến khi có sẵn các mục do lệnh gọi
from threading import Thread

def square_numbers():
    for i in range(1000):
        result = i * i


if __name__ == "__main__":        
    threads = []
    num_threads = 10

    # create threads and asign a function for each thread
    for i in range(num_threads):
        thread = Thread(target=square_numbers)
        threads.append(thread)

    # start all threads
    for thread in threads:
        thread.start()

    # wait for all threads to finish
    # block the main thread until these threads are finished
    for thread in threads:
        thread.join()
40 bị chặn. Khi các mục có sẵn, chúng được xử lý (i. e. vừa được in ở đây), sau đó
from threading import Thread

def square_numbers():
    for i in range(1000):
        result = i * i


if __name__ == "__main__":        
    threads = []
    num_threads = 10

    # create threads and asign a function for each thread
    for i in range(num_threads):
        thread = Thread(target=square_numbers)
        threads.append(thread)

    # start all threads
    for thread in threads:
        thread.start()

    # wait for all threads to finish
    # block the main thread until these threads are finished
    for thread in threads:
        thread.join()
42 thông báo cho hàng đợi rằng quá trình xử lý đã hoàn tất. Trong luồng chính, 10 luồng daemon được tạo. Điều này có nghĩa là chúng tự động chết khi luồng chính chết, và do đó, phương thức worker và vòng lặp vô hạn không còn được gọi nữa. Sau đó, hàng đợi chứa đầy các mục và phương thức worker có thể tiếp tục với các mục có sẵn. Cuối cùng,
from threading import Thread

def square_numbers():
    for i in range(1000):
        result = i * i


if __name__ == "__main__":        
    threads = []
    num_threads = 10

    # create threads and asign a function for each thread
    for i in range(num_threads):
        thread = Thread(target=square_numbers)
        threads.append(thread)

    # start all threads
    for thread in threads:
        thread.start()

    # wait for all threads to finish
    # block the main thread until these threads are finished
    for thread in threads:
        thread.join()
44 là cần thiết để chặn chủ đề chính cho đến khi tất cả các mục đã được nhận và xử lý

Start value:  0
End value: 1
end main
2

Start value:  0
End value: 1
end main
3

chủ đề daemon

Trong ví dụ trên, daemon thread được sử dụng. Các luồng daemon là các luồng nền tự động chết khi chương trình chính kết thúc. Đây là lý do tại sao có thể thoát khỏi các vòng lặp vô hạn bên trong các phương thức worker. Nếu không có quy trình daemon, chúng tôi sẽ phải sử dụng cơ chế báo hiệu, chẳng hạn như

from threading import Thread

def square_numbers():
    for i in range(1000):
        result = i * i


if __name__ == "__main__":        
    threads = []
    num_threads = 10

    # create threads and asign a function for each thread
    for i in range(num_threads):
        thread = Thread(target=square_numbers)
        threads.append(thread)

    # start all threads
    for thread in threads:
        thread.start()

    # wait for all threads to finish
    # block the main thread until these threads are finished
    for thread in threads:
        thread.join()
51 để dừng worker. Nhưng hãy cẩn thận với các quy trình daemon. Họ đột ngột dừng lại và tài nguyên của họ (e. g. tệp mở hoặc giao dịch cơ sở dữ liệu) có thể không được phát hành/hoàn thành đúng cách

Là danh sách trong chủ đề Python

Danh sách có thể được tạo thành chuỗi an toàn bằng cách sử dụng khóa loại trừ lẫn nhau (mutex) . Cụ thể, mỗi lần thêm, xóa, cập nhật và đọc danh sách phải được bảo vệ bằng khóa. Điều này có thể đạt được bằng cách gói một danh sách với một lớp mới.

Là chủ đề pop danh sách Python

pop() hoạt động là nguyên tử, có nghĩa là chúng sẽ không bị gián đoạn bởi một luồng khác. Vì vậy, nếu bạn hạn chế chỉ sử dụng. chắp thêm() và. pop() , thì chuỗi của bạn sẽ an toàn .

Là chủ đề danh sách

Tạo Danh sách trống. Nó thực hiện giao diện Danh sách. Đây là biến thể an toàn cho luồng của ArrayList . T đại diện chung.

Tại sao danh sách không phải là chủ đề

An toàn cho chuỗi có nghĩa là bất kỳ thao tác nào sửa đổi danh sách sẽ cần phải được khóa liên động để truy cập đồng thời . Điều này sẽ cần thiết ngay cả đối với những danh sách sẽ chỉ được sử dụng bởi một luồng duy nhất. Điều đó sẽ rất kém hiệu quả. Lưu câu trả lời này.