Đa luồng trong Python với ví dụ: Tìm hiểu GIL trong Python

Ngôn ngữ lập trình Python cho phép bạn sử dụng đa xử lý hoặc đa luồng. Trong hướng dẫn này, bạn sẽ học cách viết các ứng dụng đa luồng trong Python.

Chủ đề là gì?

Một luồng là một đơn vị thực thi trên lập trình đồng thời. Đa luồng là một kỹ thuật cho phép CPU thực thi nhiều tác vụ của một tiến trình cùng một lúc. Các luồng này có thể thực thi riêng lẻ trong khi chia sẻ tài nguyên tiến trình của chúng.

Một quy trình là gì?

Một quy trình về cơ bản là chương trình đang được thực thi. Khi bạn khởi động một ứng dụng trong máy tính (như trình duyệt hoặc trình soạn thảo văn bản), hệ điều hành sẽ tạo một quá trình.

Đa luồng trong Python?

Đa luồng trong Python lập trình là một kỹ thuật nổi tiếng trong đó nhiều luồng trong một tiến trình chia sẻ không gian dữ liệu của chúng với luồng chính, giúp việc chia sẻ thông tin và liên lạc trong các luồng trở nên dễ dàng và hiệu quả. Chủ đề nhẹ hơn quy trình. Nhiều luồng có thể thực thi riêng lẻ trong khi chia sẻ tài nguyên tiến trình của chúng. Mục đích của đa luồng là chạy nhiều tác vụ và ô chức năng cùng một lúc.

Đa xử lý là gì?

Đa xử lý cho phép bạn chạy nhiều tiến trình không liên quan cùng lúc. Các tiến trình này không chia sẻ tài nguyên của chúng và giao tiếp thông qua IPC.

Python Đa luồng vs Đa xử lý

Để hiểu các quy trình và luồng, hãy xem xét tình huống này: Tệp .exe trên máy tính của bạn là một chương trình. Khi bạn mở nó, hệ điều hành sẽ tải nó vào bộ nhớ và CPU sẽ thực thi nó. Phiên bản của chương trình hiện đang chạy được gọi là tiến trình.

Mỗi quá trình sẽ có 2 thành phần cơ bản:

  • Mật mã
  • Dữ liệu

Bây giờ, một tiến trình có thể chứa một hoặc nhiều phần con được gọi là chủ đề. Điều này phụ thuộc vào kiến ​​trúc hệ điều hành. Bạn có thể nghĩ về một luồng như một phần của quy trình có thể được hệ điều hành thực thi riêng biệt.

Nói cách khác, đó là một luồng hướng dẫn có thể được HĐH chạy độc lập. Các luồng trong một quy trình chia sẻ dữ liệu của quy trình đó và được thiết kế để hoạt động cùng nhau nhằm tạo điều kiện thuận lợi cho quá trình song song.

Tại sao nên sử dụng Đa luồng?

Đa luồng cho phép bạn chia nhỏ ứng dụng thành nhiều tác vụ phụ và chạy các tác vụ này cùng lúc. Nếu bạn sử dụng đa luồng đúng cách, tốc độ, hiệu suất và khả năng hiển thị của ứng dụng đều có thể được cải thiện.

Python Đa luồng

Python hỗ trợ các cấu trúc cho cả đa xử lý cũng như đa luồng. Trong hướng dẫn này, bạn sẽ chủ yếu tập trung vào việc triển khai đa luồng ứng dụng với python. Có hai mô-đun chính có thể được sử dụng để xử lý luồng trong Python:

  1. Chủ đề mô-đun, và
  2. luồng mô-đun

Tuy nhiên, trong python còn có một thứ gọi là khóa thông dịch toàn cầu (GIL). Nó không cho phép tăng hiệu suất nhiều và thậm chí có thể giảm hiệu suất của một số ứng dụng đa luồng. Bạn sẽ tìm hiểu tất cả về nó trong các phần sắp tới của hướng dẫn này.

Các mô-đun Thread và Threading

Hai mô-đun mà bạn sẽ tìm hiểu trong hướng dẫn này là mô-đun chủ đềmô-đun luồng.

Tuy nhiên, mô-đun luồng từ lâu đã không còn được dùng nữa. Bắt đầu với Python 3, nó đã được coi là lỗi thời và chỉ có thể truy cập được dưới dạng __chủ đề để tương thích ngược.

Bạn nên sử dụng cấp độ cao hơn luồng mô-đun cho các ứng dụng mà bạn dự định triển khai. Mô-đun chủ đề chỉ được đề cập ở đây cho mục đích giáo dục.

Mô-đun chủ đề

Cú pháp để tạo một chủ đề mới bằng mô-đun này như sau:

thread.start_new_thread(function_name, arguments)

Được rồi, bây giờ bạn đã nắm được lý thuyết cơ bản để bắt đầu viết mã. Vì vậy, hãy mở IDLE hoặc một cuốn sổ tay và nhập nội dung sau:

import time
import _thread

def thread_test(name, wait):
   i = 0
   while i <= 3:
      time.sleep(wait)
      print("Running %s\n" %name)
      i = i + 1

   print("%s has finished execution" %name)

if __name__ == "__main__":
    
    _thread.start_new_thread(thread_test, ("First Thread", 1))
    _thread.start_new_thread(thread_test, ("Second Thread", 2))
    _thread.start_new_thread(thread_test, ("Third Thread", 3))

Lưu file và nhấn F5 để chạy chương trình. Nếu mọi thứ đã được thực hiện chính xác thì đây là kết quả mà bạn sẽ thấy:

Mô-đun chủ đề

Bạn sẽ tìm hiểu thêm về điều kiện cuộc đua và cách xử lý chúng trong các phần sắp tới

Mô-đun chủ đề

GIẢI THÍCH MÃ

  1. Các câu lệnh này nhập mô-đun thời gian và luồng được sử dụng để xử lý việc thực thi và trì hoãn Python chủ đề.
  2. Ở đây, bạn đã xác định một hàm gọi là thread_test, cái này sẽ được gọi bởi bắt đầu_new_thread phương pháp. Hàm chạy một vòng lặp while trong bốn lần lặp và in tên của luồng gọi nó. Khi quá trình lặp hoàn tất, nó sẽ in ra một thông báo cho biết luồng đã thực hiện xong.
  3. Đây là phần chính của chương trình của bạn. Ở đây, bạn chỉ cần gọi bắt đầu_new_thread phương pháp với thread_test hàm làm đối số. Điều này sẽ tạo một luồng mới cho hàm bạn truyền làm đối số và bắt đầu thực thi nó. Lưu ý rằng bạn có thể thay thế cái này (thread_test) bằng bất kỳ hàm nào khác mà bạn muốn chạy dưới dạng một luồng.

Mô-đun luồng

Mô-đun này là cách triển khai cấp cao về phân luồng trong python và là tiêu chuẩn thực tế để quản lý các ứng dụng đa luồng. Nó cung cấp một loạt các tính năng khi so sánh với mô-đun luồng.

Cấu trúc của module Threading
Cấu trúc của module Threading

Dưới đây là danh sách một số chức năng hữu ích được xác định trong mô-đun này:

Tên chức năng Mô tả Chi tiết
hoạt độngCount() Trả về số lượng Sợi chỉ đồ vật vẫn còn sống
currentThread() Trả về đối tượng hiện tại của lớp Thread.
liệt kê () Liệt kê tất cả các đối tượng Thread đang hoạt động.
isDaemon() Trả về true nếu luồng là daemon.
isAlive () Trả về true nếu thread vẫn còn tồn tại.
Các phương thức lớp chủ đề
khởi đầu() Bắt đầu hoạt động của một chủ đề. Nó chỉ được gọi một lần cho mỗi luồng vì nó sẽ gây ra lỗi thời gian chạy nếu được gọi nhiều lần.
chạy() Phương thức này biểu thị hoạt động của một luồng và có thể bị ghi đè bởi một lớp mở rộng lớp Thread.
tham gia() Nó chặn việc thực thi mã khác cho đến khi luồng mà phương thức join() được gọi trên đó bị chấm dứt.

Cốt truyện: Lớp chủ đề

Trước khi bạn bắt đầu mã hóa các chương trình đa luồng bằng mô-đun luồng, điều quan trọng là phải hiểu về lớp Thread. Lớp luồng là lớp chính xác định mẫu và các hoạt động của một luồng trong python.

Cách phổ biến nhất để tạo một ứng dụng python đa luồng là khai báo một lớp mở rộng lớp Thread và ghi đè phương thức run() của nó.

Tóm lại, lớp Thread biểu thị một chuỗi mã chạy trong một Chủ đề kiểm soát.

Vì vậy, khi viết một ứng dụng đa luồng, bạn sẽ thực hiện như sau:

  1. định nghĩa một lớp mở rộng lớp Thread
  2. Ghi đè __trong đó__ constructor
  3. Ghi đè chạy() phương pháp

Khi một đối tượng luồng đã được tạo, khởi đầu() phương pháp có thể được sử dụng để bắt đầu thực hiện hoạt động này và tham gia() phương pháp này có thể được sử dụng để chặn tất cả các mã khác cho đến khi hoạt động hiện tại kết thúc.

Bây giờ, hãy thử sử dụng mô-đun luồng để triển khai ví dụ trước của bạn. Một lần nữa, hãy bùng nổ IDLE và nhập nội dung sau:

import time
import threading

class threadtester (threading.Thread):
    def __init__(self, id, name, i):
       threading.Thread.__init__(self)
       self.id = id
       self.name = name
       self.i = i
       
    def run(self):
       thread_test(self.name, self.i, 5)
       print ("%s has finished execution " %self.name)

def thread_test(name, wait, i):

    while i:
       time.sleep(wait)
       print ("Running %s \n" %name)
       i = i - 1

if __name__=="__main__":
    thread1 = threadtester(1, "First Thread", 1)
    thread2 = threadtester(2, "Second Thread", 2)
    thread3 = threadtester(3, "Third Thread", 3)

    thread1.start()
    thread2.start()
    thread3.start()

    thread1.join()
    thread2.join()
    thread3.join()

Đây sẽ là đầu ra khi bạn thực thi đoạn mã trên:

Cốt truyện: Lớp chủ đề

GIẢI THÍCH MÃ

Cốt truyện: Lớp chủ đề

  1. Phần này giống như ví dụ trước của chúng tôi. Ở đây, bạn nhập mô-đun thời gian và luồng được sử dụng để xử lý việc thực thi và độ trễ của Python chủ đề.
  2. Trong phần này, bạn đang tạo một lớp có tên là threadtester, lớp này kế thừa hoặc mở rộng Sợi chỉ lớp của mô-đun luồng. Đây là một trong những cách phổ biến nhất để tạo luồng trong python. Tuy nhiên, bạn chỉ nên ghi đè hàm tạo và chạy() phương pháp trong ứng dụng của bạn. Như bạn có thể thấy trong mẫu mã ở trên, __trong đó__ phương thức (hàm tạo) đã bị ghi đè. Tương tự, bạn cũng đã ghi đè chạy() phương pháp. Nó chứa mã mà bạn muốn thực thi bên trong một luồng. Trong ví dụ này, bạn đã gọi hàm thread_test().
  3. Đây là phương thức thread_test() nhận giá trị của i làm đối số, giảm nó đi 1 ở mỗi lần lặp và lặp qua phần còn lại của mã cho đến khi i trở thành 0. Trong mỗi lần lặp, nó in tên của luồng hiện đang thực thi và ngủ trong vài giây chờ (cũng được lấy làm đối số ).
  4. thread1 = threadtester(1, “First Thread”, 1) Ở đây, chúng ta đang tạo một luồng và truyền ba tham số mà chúng ta đã khai báo trong __init__. Tham số đầu tiên là id của luồng, tham số thứ hai là tên của luồng và tham số thứ ba là bộ đếm, xác định số lần vòng lặp while sẽ chạy.
  5. thread2.start()T phương thức start được sử dụng để bắt đầu thực thi một luồng. Bên trong, hàm start() gọi phương thức run() của lớp bạn.
  6. thread3.join() Phương thức join() chặn việc thực thi mã khác và đợi cho đến khi luồng mà nó được gọi kết thúc.

Như bạn đã biết, các luồng trong cùng một tiến trình có quyền truy cập vào bộ nhớ và dữ liệu của tiến trình đó. Do đó, nếu nhiều luồng cố gắng thay đổi hoặc truy cập dữ liệu cùng lúc, lỗi có thể xảy ra.

Trong phần tiếp theo, bạn sẽ thấy các loại biến chứng khác nhau có thể hiển thị khi các luồng truy cập vào dữ liệu và phần quan trọng mà không kiểm tra các giao dịch truy cập hiện có.

Bế tắc và điều kiện chạy đua

Trước khi tìm hiểu về tình trạng bế tắc và tình trạng chạy đua, bạn nên hiểu một số định nghĩa cơ bản liên quan đến lập trình đồng thời:

  • Phần quan trọng: Đây là một đoạn mã truy cập hoặc sửa đổi các biến được chia sẻ và phải được thực hiện như một giao dịch nguyên tử.
  • Chuyển đổi ngữ cảnhĐây là quá trình mà CPU thực hiện để lưu trữ trạng thái của một luồng trước khi chuyển từ tác vụ này sang tác vụ khác để có thể tiếp tục từ cùng một điểm sau đó.

Bế tắc

Bế tắc là vấn đề đáng sợ nhất mà các nhà phát triển phải đối mặt khi viết các ứng dụng đồng thời/đa luồng trong python. Cách tốt nhất để hiểu về bế tắc là sử dụng ví dụ khoa học máy tính cổ điển được gọi là Nhà Hàng PhiloVấn đề sophers.

Câu hỏi đặt ra cho các triết gia ăn uống như sau:

Năm nhà triết học ngồi quanh một chiếc bàn tròn với năm đĩa mì spaghetti (một loại mì ống) và năm chiếc nĩa, như thể hiện trong sơ đồ.

Nhà Hàng Philovấn đề sophers

Nhà Hàng Philovấn đề sophers

Vào bất kỳ thời điểm nào, một triết gia phải đang ăn hoặc đang suy nghĩ.

Hơn nữa, một triết gia phải lấy hai chiếc nĩa gần mình (tức là nĩa trái và nĩa phải) trước khi có thể ăn mì spaghetti. Vấn đề bế tắc xảy ra khi cả năm triết gia cùng cầm nĩa phải của mình lên cùng một lúc.

Vì mỗi triết gia đều có một chiếc nĩa, nên họ sẽ đợi những người khác đặt nĩa xuống. Kết quả là không ai trong số họ có thể ăn được mì spaghetti.

Tương tự như vậy, trong một hệ thống đồng thời, bế tắc xảy ra khi các luồng hoặc quy trình khác nhau (philosophers) cố gắng có được các tài nguyên hệ thống được chia sẻ (fork) cùng một lúc. Kết quả là, không có quy trình nào có cơ hội thực thi vì chúng đang chờ một tài nguyên khác do một quy trình khác nắm giữ.

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

Tình trạng chạy đua là trạng thái không mong muốn của một chương trình xảy ra khi hệ thống thực hiện hai hoặc nhiều thao tác cùng lúc. Ví dụ, hãy xem xét vòng lặp for đơn giản này:

i=0; # a global variable
for x in range(100):
    print(i)
    i+=1;

Nếu bạn tạo n số luồng chạy mã này cùng một lúc, bạn không thể xác định giá trị của i (được chia sẻ bởi các luồng) khi chương trình kết thúc thực thi. Điều này là do trong môi trường đa luồng thực, các luồng có thể chồng lên nhau và giá trị của i được một luồng truy xuất và sửa đổi có thể thay đổi khi một số luồng khác truy cập vào nó.

Đây là hai loại vấn đề chính có thể xảy ra trong ứng dụng Python đa luồng hoặc phân tán. Trong phần tiếp theo, bạn sẽ học cách khắc phục vấn đề này bằng cách đồng bộ hóa luồng.

Syncchủ đề đồng bộ hóa

Để giải quyết các tình trạng chạy đua, bế tắc và các vấn đề dựa trên luồng khác, mô-đun luồng cung cấp Khóa object. Ý tưởng là khi một luồng muốn truy cập vào một tài nguyên cụ thể, nó sẽ có được một khóa cho tài nguyên đó. Khi một luồng khóa một tài nguyên cụ thể, không luồng nào khác có thể truy cập vào tài nguyên đó cho đến khi khóa được giải phóng. Kết quả là, các thay đổi đối với tài nguyên sẽ là nguyên tử và các điều kiện chạy đua sẽ được ngăn chặn.

Khóa là một nguyên thủy đồng bộ hóa cấp thấp được triển khai bởi __chủ đề mô-đun. Tại bất kỳ thời điểm nào, khóa có thể ở một trong 2 trạng thái: khóa or đã mở khóa. Nó hỗ trợ hai phương pháp:

  1. giành được()Khi trạng thái khóa được mở khóa, việc gọi phương thức thu được() sẽ thay đổi trạng thái thành bị khóa và quay trở lại. Tuy nhiên, nếu trạng thái bị khóa, lệnh gọi hàm thu được() sẽ bị chặn cho đến khi phương thức phát hành() được một số luồng khác gọi.
  2. phóng thích()Phương thức phát hành () được sử dụng để đặt trạng thái thành đã mở khóa, tức là để giải phóng khóa. Nó có thể được gọi bởi bất kỳ luồng nào, không nhất thiết phải là luồng đã lấy được khóa.

Đây là ví dụ về cách sử dụng khóa trong ứng dụng của bạn. Hãy bùng cháy lên IDLE và nhập nội dung sau:

import threading
lock = threading.Lock()

def first_function():
    for i in range(5):
        lock.acquire()
        print ('lock acquired')
        print ('Executing the first funcion')
        lock.release()

def second_function():
    for i in range(5):
        lock.acquire()
        print ('lock acquired')
        print ('Executing the second funcion')
        lock.release()

if __name__=="__main__":
    thread_one = threading.Thread(target=first_function)
    thread_two = threading.Thread(target=second_function)

    thread_one.start()
    thread_two.start()

    thread_one.join()
    thread_two.join()

Bây giờ, nhấn F5. Bạn sẽ thấy một kết quả như thế này:

Syncchủ đề đồng hồ hóa

GIẢI THÍCH MÃ

Syncchủ đề đồng hồ hóa

  1. Ở đây, bạn chỉ cần tạo một khóa mới bằng cách gọi luồng.Lock() chức năng của nhà máy. Trong nội bộ, Lock() trả về một phiên bản của lớp Lock cụ thể hiệu quả nhất được nền tảng duy trì.
  2. Trong câu lệnh đầu tiên, bạn lấy được khóa bằng cách gọi phương thức thu được(). Khi khóa đã được cấp, bạn in “đã lấy được khóa” đến bảng điều khiển. Khi tất cả mã mà bạn muốn luồng chạy đã thực thi xong, bạn giải phóng khóa bằng cách gọi phương thức Release().

Về lý thuyết thì ổn, nhưng làm sao bạn biết được chiếc khóa đó thực sự hoạt động? Nếu nhìn vào kết quả, bạn sẽ thấy rằng mỗi câu lệnh in đang in chính xác một dòng mỗi lần. Hãy nhớ lại rằng, trong một ví dụ trước đó, kết quả đầu ra từ print có sự lộn xộn vì nhiều luồng đang truy cập phương thức print() cùng một lúc. Ở đây, chức năng in chỉ được gọi sau khi có được khóa. Vì vậy, các kết quả đầu ra được hiển thị lần lượt và từng dòng.

Ngoài khóa, Python còn hỗ trợ một số cơ chế khác để xử lý đồng bộ hóa luồng như được liệt kê dưới đây:

  1. RKhóa
  2. Semaphores
  3. Điều kiện
  4. Sự kiện và
  5. Rào cản

Khóa phiên dịch toàn cầu (và cách xử lý nó)

Trước khi đi sâu vào chi tiết về GIL của python, chúng ta hãy định nghĩa một số thuật ngữ sẽ hữu ích để hiểu phần tiếp theo:

  1. Mã liên kết với CPU: điều này đề cập đến bất kỳ đoạn mã nào sẽ được CPU thực thi trực tiếp.
  2. Mã giới hạn I/O: đây có thể là bất kỳ mã nào truy cập vào hệ thống tệp thông qua hệ điều hành
  3. CPython: đó là tài liệu tham khảo thực hiện of Python và có thể được mô tả như trình thông dịch được viết bằng C và Python (ngôn ngữ lập trình).

GIL trong đó là gì Python?

Khóa thông dịch viên toàn cầu (GIL) trong python là khóa tiến trình hoặc mutex được sử dụng khi xử lý các tiến trình. Nó đảm bảo rằng một luồng có thể truy cập một tài nguyên cụ thể tại một thời điểm và nó cũng ngăn việc sử dụng các đối tượng và mã byte cùng một lúc. Điều này mang lại lợi ích cho các chương trình đơn luồng trong việc tăng hiệu suất. GIL trong python rất đơn giản và dễ thực hiện.

Khóa có thể được sử dụng để đảm bảo rằng chỉ có một luồng có quyền truy cập vào một tài nguyên cụ thể tại một thời điểm nhất định.

Một trong những tính năng của Python là nó sử dụng khóa toàn cục trên mỗi tiến trình thông dịch, nghĩa là mọi tiến trình đều coi trình thông dịch Python là một tài nguyên.

Ví dụ: giả sử bạn đã viết một chương trình python sử dụng hai luồng để thực hiện cả hoạt động CPU và 'I/O'. Khi bạn thực hiện chương trình này, điều này sẽ xảy ra:

  1. Trình thông dịch python tạo một tiến trình mới và sinh ra các luồng
  2. Khi thread-1 bắt đầu chạy, trước tiên nó sẽ lấy GIL và khóa nó.
  3. Nếu thread-2 muốn thực thi ngay bây giờ, nó sẽ phải đợi GIL được giải phóng ngay cả khi bộ xử lý khác rảnh.
  4. Bây giờ, giả sử luồng-1 đang chờ thao tác I/O. Tại thời điểm này, nó sẽ giải phóng GIL và thread-2 sẽ thu được nó.
  5. Sau khi hoàn thành các thao tác I/O, nếu luồng-1 muốn thực thi ngay bây giờ, nó sẽ lại phải đợi GIL được giải phóng bởi luồng-2.

Do đó, chỉ có một luồng có thể truy cập trình thông dịch bất kỳ lúc nào, nghĩa là sẽ chỉ có một luồng thực thi mã python tại một thời điểm nhất định.

Điều này ổn trong bộ xử lý lõi đơn vì nó sẽ sử dụng tính năng cắt thời gian (xem phần đầu tiên của hướng dẫn này) để xử lý các luồng. Tuy nhiên, trong trường hợp bộ xử lý đa lõi, chức năng gắn với CPU thực thi trên nhiều luồng sẽ có tác động đáng kể đến hiệu suất của chương trình vì nó thực sự không sử dụng tất cả các lõi có sẵn cùng một lúc.

Tại sao cần GIL?

CPython Trình thu gom rác sử dụng một kỹ thuật quản lý bộ nhớ hiệu quả được gọi là đếm tham chiếu. Đây là cách thức hoạt động: Mỗi đối tượng trong python đều có một số tham chiếu, số này tăng lên khi được gán cho một tên biến mới hoặc được thêm vào một vùng chứa (như bộ, danh sách, v.v.). Tương tự như vậy, số tham chiếu giảm xuống khi tham chiếu nằm ngoài phạm vi hoặc khi câu lệnh del được gọi. Khi số tham chiếu của một đối tượng đạt đến 0, nó sẽ được thu gom rác và bộ nhớ được phân bổ sẽ được giải phóng.

Nhưng vấn đề là biến đếm tham chiếu dễ bị tình trạng chạy đua như bất kỳ biến toàn cục nào khác. Để giải quyết vấn đề này, các nhà phát triển python đã quyết định sử dụng khóa thông dịch toàn cục. Một lựa chọn khác là thêm khóa vào mỗi đối tượng, điều này sẽ dẫn đến tình trạng bế tắc và tăng chi phí từ các lệnh gọi acquire() và release().

Do đó, GIL là một hạn chế đáng kể đối với các chương trình python đa luồng chạy các hoạt động nặng liên quan đến CPU (làm cho chúng trở thành đơn luồng một cách hiệu quả). Nếu bạn muốn sử dụng nhiều lõi CPU trong ứng dụng của mình, hãy sử dụng đa xử lý mô-đun thay thế.

Tổng kết

  • Python hỗ trợ 2 mô-đun cho đa luồng:
    1. __chủ đề mô-đun: Nó cung cấp triển khai cấp thấp cho phân luồng và đã lỗi thời.
    2. mô-đun luồng: Nó cung cấp triển khai đa luồng ở mức cao và là tiêu chuẩn hiện tại.
  • Để tạo luồng bằng mô-đun luồng, bạn phải thực hiện như sau:
    1. Tạo một lớp mở rộng Sợi chỉ lớp học.
    2. Ghi đè hàm tạo của nó (__init__).
    3. Ghi đè nó chạy() phương pháp.
    4. Tạo một đối tượng của lớp này.
  • Một luồng có thể được thực thi bằng cách gọi khởi đầu() phương pháp.
  • tham gia() phương thức này có thể được sử dụng để chặn các luồng khác cho đến khi luồng này (luồng được gọi trên đó) kết thúc quá trình thực thi.
  • Tình trạng dồn đuổi xảy ra khi nhiều luồng truy cập hoặc sửa đổi tài nguyên được chia sẻ cùng một lúc.
  • Nó có thể tránh được bằng cách Syncchủ đề đồng bộ hóa.
  • Python hỗ trợ 6 cách để đồng bộ hóa luồng:
    1. Khóa
    2. RKhóa
    3. Semaphores
    4. Điều kiện
    5. Sự kiện và
    6. Rào cản
  • Khóa chỉ cho phép một luồng cụ thể đã có khóa đi vào phần quan trọng.
  • Khóa có 2 phương thức chính:
    1. giành được(): Nó đặt trạng thái khóa thành bị khóa. Nếu được gọi trên một đối tượng bị khóa, nó sẽ chặn cho đến khi tài nguyên trống.
    2. phóng thích(): Nó đặt trạng thái khóa thành mở khóa và trở lại. Nếu được gọi trên một đối tượng đã được mở khóa, nó sẽ trả về sai.
  • Khóa trình thông dịch toàn cục là một cơ chế trong đó chỉ có 1 CPython quá trình thông dịch có thể thực hiện tại một thời điểm.
  • Nó được sử dụng để hỗ trợ chức năng đếm tham chiếu của CPythonngười thu gom rác của s.
  • Để thực hiện Python Đối với các ứng dụng có hoạt động chiếm nhiều CPU, bạn nên sử dụng mô-đun đa xử lý.