Đa luồng hoạt động như thế nào trong Python?

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

Quy trình là gì?

Một quy trình về cơ bản là chương trình đang thực thi. Khi bạn khởi động một ứng dụng trong máy tính của mình (chẳng hạn 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 quy trình

Đa luồng trong Python là gì?

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

Trong hướng dẫn này, bạn sẽ học,

Đa xử lý là gì?

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

Đa luồng Python 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. Một. 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ó. Thể hiện của chương trình hiện đang chạy được gọi là tiến trình

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

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

Giờ đây, một quy trình có thể chứa một hoặc nhiều phần con được gọi là luồng. Đ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 thực thi riêng bởi hệ điều hành

Nói cách khác, đó là một luồng lệnh mà HĐH có thể 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 xử lý 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 đồng thời. Nếu bạn sử dụng đa luồng đúng cách, thì tốc độ, hiệu suất và kết xuất ứng dụng của bạn đều có thể được cải thiện

Đa luồng Python

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 triển khai các ứng dụng đa luồng với python. Có hai mô-đun chính có thể được sử dụng để xử lý các luồng trong Python

  1. Mô-đun luồng và
  2. mô-đun luồng

Tuy nhiên, trong python, còn có một thứ gọi là khóa phiên 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ể làm 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 luồng và mô-đun phân luồng

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

Bạn nên sử dụng mô-đun luồng cấp cao hơn cho các ứng dụng mà bạn đị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 notepad của bạn 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, đây là đầu ra mà bạn sẽ thấy

Đa luồng hoạt động như thế nào trong Python?

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

Đa luồng hoạt động như thế nào trong Python?

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 các luồng Python
  2. Ở đây, bạn đã định nghĩa một hàm gọi là thread_test, hàm này sẽ được gọi bởi phương thức start_new_thread. Hàm chạy một vòng lặp while trong bốn lần lặp lại và in tên của chuỗi đã gọi nó. Khi quá trình lặp hoàn tất, nó sẽ in 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. Tại đây, bạn chỉ cần gọi phương thức start_new_thread với hàm thread_test làm đối số. Thao tác này sẽ tạo một luồng mới cho hàm bạn chuyển làm đối số và bắt đầu thực thi nó. Lưu ý rằng bạn có thể thay thế (thread_test) này bằng bất kỳ chức năng nào khác mà bạn muốn chạy dưới dạng một chuỗi

Mô-đun luồng

Mô-đun này là triển khai luồng cấp cao trong python và 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

Đa luồng hoạt động như thế nào trong Python?
Cấu trúc của mô-đun 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

Hàm NameDescriptionactiveCount()Trả về số đối tượng Thread vẫn còn tồn tạicurrentThread()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 Chủ đề đang hoạt động. isDaemon()Trả về true nếu luồng là daemon. isAlive()Trả về true nếu thread vẫn tồn tại. Các phương thức của lớp Threadstart() Bắt đầu hoạt động của một luồng. 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. run() 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 tham gia () được gọi 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 Chủ đề. 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 luồng điều khiển riêng biệt

Vậy khi viết app đa luồng các bạn sẽ làm như sau

  1. định nghĩa một lớp mở rộng lớp Thread
  2. Ghi đè hàm tạo __init__
  3. Ghi đè phương thức run()

Khi một đối tượng luồng đã được tạo, phương thức start() có thể được sử dụng để bắt đầu thực thi hoạt động này và phương thức join() 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, kích hoạt IDLE của bạn và gõ như 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

Đa luồng hoạt động như thế nào trong Python?

GIẢI THÍCH MÃ

Đa luồng hoạt động như thế nào trong Python?

  1. Phần này giống như ví dụ trước của chúng tôi. 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 các luồng Python
  2. Trong đoạ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 lớp Thread của mô-đun luồng. Đây là một trong những cách phổ biến nhất để tạo chủ đề trong python. Tuy nhiên, bạn chỉ nên ghi đè hàm tạo và phương thức run() trong ứng dụng của mình. Như bạn có thể thấy trong đoạn mã mẫu ở trên, phương thức __init__ (hàm tạo) đã bị ghi đè. Tương tự, bạn cũng đã ghi đè phương thức run(). 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() lấy 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 (cũng được coi là đối số)
  4. thread1 = threadtester(1, “First Thread”, 1) Ở đây, chúng tôi đang tạo một luồng và chuyển ba tham số mà chúng tôi đã 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. chủ đề2. start() 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. chủ đề3. tham gia () Phương thức tham gia () 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 quy trình có quyền truy cập vào bộ nhớ và dữ liệu của quy trình đó. Do đó, nếu có nhiều hơn một luồng cố gắng thay đổi hoặc truy cập dữ liệu đồng thời, lỗi có thể xuất hiện.

Trong phần tiếp theo, bạn sẽ thấy các loại phức tạp khác nhau có thể hiển thị khi các luồng truy cập 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 cuộc đua

Trước khi tìm hiểu về bế tắc và điều kiện chủng tộc, sẽ rất hữu ích nếu bạ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Đó 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Đó là quá trình mà CPU tuân theo để lưu trữ trạng thái của một luồng trước khi thay đổi từ tác vụ này sang tác vụ khác để có thể tiếp tục lại 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 gặp phải khi viết các ứng dụng đồng thời/đa luồng trong python. Cách tốt nhất để hiểu bế tắc là sử dụng bài toán ví dụ về khoa học máy tính cổ điển được gọi là Bài toán nhà triết học ăn uống

Tuyên bố vấn đề cho các triết gia ăn uống như sau

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

Đa luồng hoạt động như thế nào trong Python?
Vấn đề triết gia ăn uống

Tại 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 cái nĩa liền kề với mình (i. e. , nĩa trái và phải) trước khi anh ấy có thể ăn mì spaghetti. Vấn đề bế tắc xảy ra khi cả năm nhà triết học cùng lúc nhặt chiếc nĩa bên phải của họ

Vì mỗi nhà triết học có một cái nĩa, nên tất cả 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 spaghetti

Tương tự, 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 (các triết gia) cố gắng lấy các tài nguyên hệ thống được chia sẻ (các nhánh) 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 số quy trình khác nắm giữ

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

Điều kiện tương tranh là trạng thái không mong muốn của chương trình xảy ra khi hệ thống thực hiện đồng thời hai thao tác trở lên. Ví dụ, 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 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ể trùng lặp và giá trị của i được một luồng truy xuất và sửa đổi có thể thay đổi giữa chừng khi một số luồng khác truy cập vào nó

Đây là hai loại sự cố 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ẽ tìm hiểu cách khắc phục sự cố này bằng cách đồng bộ hóa các chủ đề

Đồng bộ chủ đề

Để xử lý các điều kiện chủng tộc, bế tắc và các vấn đề dựa trên luồng khác, mô-đun luồng cung cấp đối tượng Khóa. Ý 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ẽ nhận được khóa cho tài nguyên đó. Khi một luồng khóa một tài nguyên cụ thể, không có luồng nào khác có thể truy cập tài nguyên đó cho đến khi khóa được giải phóng. Do đó, các thay đổi đối với tài nguyên sẽ là nguyên tử và các điều kiện chủng tộc sẽ được ngăn chặn

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

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

Đây là một ví dụ về việc sử dụng khóa trong ứng dụng của bạn. Kích hoạt IDLE của bạn và gõ như 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 đầu ra như thế này

Đa luồng hoạt động như thế nào trong Python?

GIẢI THÍCH MÃ

Đa luồng hoạt động như thế nào trong Python?

  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 xuất xưởng. Bên trong, Lock() trả về một thể hiện của lớp Lock cụ thể hiệu quả nhất được duy trì bởi nền tảng
  2. Trong câu lệnh đầu tiên, bạn có được khóa bằng cách gọi phương thức thu thập (). Khi khóa đã được cấp, bạn in “đã nhận được khóa” ra bàn đ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()

Lý thuyết là tốt, nhưng làm thế nào để bạn biết rằng khóa thực sự hoạt động? . Nhớ lại rằng, trong một ví dụ trước đó, kết quả đầu ra từ bản in 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à theo từng dòng

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

  1. RLocks
  2. đèn hiệu
  3. Điều kiện
  4. Sự kiện, và
  5. rào cản

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

Trước khi tìm hiểu chi tiết về GIL của python, hãy xác định một vài thuật ngữ sẽ hữu ích để hiểu phần sắp tới

  1. mã giới hạn 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 hệ thống tệp thông qua hệ điều hành
  3. CPython. nó là triển khai tham chiếu của Python và có thể được mô tả là trình thông dịch được viết bằng C và Python (ngôn ngữ lập trình)

GIL trong Python là gì?

Khóa phiên dịch toàn cầu (GIL) trong python là khóa quy trình hoặc một mutex được sử dụng trong khi xử lý các quy trình. Nó đảm bảo rằng một luồng có thể truy cập vào 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

Một khóa có thể được sử dụng để đảm bảo rằng chỉ 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 quy trình thông dịch viên, điều đó có nghĩa là mọi quy trình đều coi chính trình thông dịch python là 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 của CPU và 'I/O'. Khi bạn thực hiện chương trình này, đây là điều sẽ xảy ra

  1. Trình thông dịch python tạo một quy trình mới và sinh ra các luồng
  2. Khi thread-1 bắt đầu chạy, đầu tiên nó sẽ lấy GIL và khóa nó
  3. Nếu luồng-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à luồng-2 sẽ lấy nó
  5. Sau khi hoàn thành 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ỉ 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 không sao trong bộ xử lý lõi đơn vì nó sẽ sử dụng cắt lá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 liên kết với CPU thực thi trên nhiều luồng sẽ có tác động đáng kể đến hiệu quả của chương trình vì nó sẽ không thực sự sử dụng tất cả các lõi có sẵn cùng một lúc

Tại sao GIL lại cần thiết?

Trình thu gom rác CPython 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 nó hoạt động. Mọi đối tượng trong python đều có số lượng tham chiếu, số lượng này được tăng lên khi nó đượ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ộ dữ liệu, danh sách, v.v. ). Tương tự như vậy, số tham chiếu bị giảm khi tham chiếu nằm ngoài phạm vi hoặc khi câu lệnh del được gọi. Khi số lượng tham chiếu của một đối tượng đạt đến 0, nó sẽ được thu thập rác và bộ nhớ được phân bổ sẽ được giải phóng

Nhưng vấn đề là biến số đếm tham chiếu dễ bị điều kiện chủng tộc 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 trình thông dịch toàn cầu. Tùy chọn khác là thêm một khóa cho từng đối tượng, điều này sẽ dẫn đến bế tắc và tăng chi phí hoạt động từ các cuộc gọi thu được () và phát hành ()

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 liên quan đến CPU nặng (làm cho chúng trở thành một 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 mô-đun đa xử lý để thay thế

Đa luồng hoạt động như thế nào trong Python?

Đa luồng (đôi khi chỉ đơn giản là "phân luồng") là khi một chương trình tạo nhiều luồng với chu kỳ thực thi giữa chúng, do đó, một tác vụ chạy lâu hơn không chặn tất cả các tác vụ khác. This works well for tasks that can be broken down into smaller subtasks, which can then each be given to a thread to be completed.

Sử dụng đa luồng trong Python có tốt không?

Đa luồng trong Python hợp lý hóa việc sử dụng tài nguyên hiệu quả vì các luồng chia sẻ cùng một bộ nhớ và không gian dữ liệu . Nó cũng cho phép xuất hiện đồng thời nhiều tác vụ và giảm thời gian phản hồi. Điều này cải thiện hiệu suất.

Đa luồng hoạt động như thế nào?

Với đa luồng, trong khi bộ xử lý của hệ thống máy tính thực hiện một lệnh tại một thời điểm, các luồng khác nhau từ nhiều chương trình được thực thi nhanh đến mức có vẻ như các chương trình được thực thi đồng thời

Nhiều luồng có thể chạy cùng lúc Python không?

Trên thực tế, một quy trình Python không thể chạy các luồng song song nhưng nó có thể chạy chúng đồng thời thông qua chuyển đổi ngữ cảnh trong các hoạt động liên kết I/O . Hạn chế này thực sự được thi hành bởi GIL. Khóa phiên dịch toàn cầu Python (GIL) ngăn các luồng trong cùng một quy trình được thực thi cùng một lúc.