Là chủ đề số nguyên Python

Trong hướng dẫn này, chúng tôi sẽ chỉ cho bạn cách đạt được tính song song trong mã của bạn bằng cách sử dụng các kỹ thuật đa luồng trong Python

"Song song", "đa luồng"— những thuật ngữ này có nghĩa là gì và chúng liên quan như thế nào?

  • Đồng thời là gì?
  • Sự khác biệt giữa đồng thời và song song là gì?
  • Sự khác biệt giữa các quy trình và chủ đề là gì?
  • Đa luồng trong Python là gì?
  • Khóa phiên dịch toàn cầu là gì?

Ở đây chúng tôi giả định rằng bạn đã biết các nguyên tắc cơ bản của Python, bao gồm các cấu trúc và chức năng cơ bản. Nếu bạn không quen với những điều này (hoặc háo hức tìm hiểu), hãy thử Kiến thức cơ bản về Python để phân tích dữ liệu – Dataquest của chúng tôi

Đồng thời là gì?

Trước khi đi vào chi tiết đa luồng, hãy so sánh lập trình đồng thời với lập trình tuần tự

Trong tính toán tuần tự, các thành phần của chương trình được thực hiện từng bước để tạo ra kết quả chính xác; . Do đó, bộ xử lý có thể chạy các thành phần ở các trạng thái khác nhau một cách độc lập và đồng thời. Ưu điểm chính của đồng thời là cải thiện thời gian chạy của chương trình, điều đó có nghĩa là vì bộ xử lý chạy các tác vụ độc lập đồng thời nên bộ xử lý cần ít thời gian hơn để chạy toàn bộ chương trình và hoàn thành tác vụ chính

Sự khác biệt giữa đồng thời và song song là gì?

Đồng thời là một điều kiện trong đó hai hoặc nhiều tác vụ có thể được bắt đầu và hoàn thành trong các khoảng thời gian chồng chéo trên một bộ xử lý và lõi. Tính song song là một điều kiện trong đó nhiều tác vụ hoặc các phần phân tán của một tác vụ chạy độc lập và đồng thời trên nhiều bộ xử lý. Vì vậy, không thể xử lý song song trên các máy có bộ xử lý đơn và lõi đơn

Hãy tưởng tượng hai hàng khách hàng; . Song song có nghĩa là hai nhân viên thu ngân đồng thời phục vụ hai hàng đợi của khách hàng

Sự khác biệt giữa các quy trình và chủ đề là gì?

Một quy trình là một chương trình đang thực thi với không gian địa chỉ, bộ nhớ, ngăn xếp dữ liệu, v.v. Hệ điều hành phân bổ tài nguyên cho các quy trình và quản lý việc thực thi của các quy trình bằng cách gán thời gian CPU cho các quy trình thực thi khác nhau, theo bất kỳ chiến lược lập lịch nào

Chủ đề tương tự như các quy trình. Tuy nhiên, chúng thực thi trong cùng một quy trình và chia sẻ cùng một bối cảnh. Do đó, việc chia sẻ thông tin hoặc giao tiếp với các luồng khác dễ truy cập hơn nếu chúng là các quy trình riêng biệt

Đa luồng trong Python

Máy ảo Python không phải là trình thông dịch an toàn cho luồng, nghĩa là trình thông dịch chỉ có thể thực thi một luồng tại bất kỳ thời điểm nào. Giới hạn này được thực thi bởi Khóa thông dịch viên toàn cầu Python (GIL), về cơ bản giới hạn một chuỗi Python chạy tại một thời điểm. Nói cách khác, GIL đảm bảo rằng chỉ có một luồng chạy trong cùng một quy trình tại cùng một thời điểm trên một bộ xử lý

Về cơ bản, luồng có thể không tăng tốc tất cả các tác vụ. Các tác vụ liên quan đến I/O dành nhiều thời gian chờ đợi các sự kiện bên ngoài có cơ hội tận dụng lợi thế của luồng tốt hơn so với các tác vụ liên quan đến CPU


GHI CHÚ

Python đi kèm với hai mô-đun tích hợp để triển khai các chương trình đa luồng, bao gồm mô-đun threadthreading. Các mô-đun threadthreading cung cấp các tính năng hữu ích để tạo và quản lý chuỗi. Tuy nhiên, trong hướng dẫn này, chúng ta sẽ tập trung vào mô-đun threading, đây là mô-đun cấp cao, được cải tiến nhiều để triển khai các chương trình đa luồng nghiêm túc. Ngoài ra, Python cung cấp mô-đun

numbers = [2, 3, 5, 8]
start = time.time()
calc_square(numbers)
calc_cube(numbers)
end = time.time()

print('Execution Time: {}'.format(end-start))
1, cho phép chúng tôi tạo cấu trúc dữ liệu hàng đợi để trao đổi thông tin qua nhiều luồng một cách an toàn


Hãy bắt đầu với một ví dụ đơn giản để hiểu lợi ích của việc sử dụng lập trình đa luồng

Giả sử chúng ta có một danh sách các số nguyên và chúng ta sẽ tính bình phương và lập phương của mỗi số này rồi in chúng ra màn hình

Chương trình này bao gồm hai nhiệm vụ (chức năng) riêng biệt như sau

import time
def calc_square(numbers):
    for n in numbers:
        print(f'\n{n} ^ 2 = {n*n}')
        time.sleep(0.1)

def calc_cube(numbers):
    for n in numbers:
        print(f'\n{n} ^ 3 = {n*n*n}')
        time.sleep(0.1)

Đoạn mã trên thực hiện hai chức năng,

numbers = [2, 3, 5, 8]
start = time.time()
calc_square(numbers)
calc_cube(numbers)
end = time.time()

print('Execution Time: {}'.format(end-start))
2 và
numbers = [2, 3, 5, 8]
start = time.time()
calc_square(numbers)
calc_cube(numbers)
end = time.time()

print('Execution Time: {}'.format(end-start))
3. Hàm
numbers = [2, 3, 5, 8]
start = time.time()
calc_square(numbers)
calc_cube(numbers)
end = time.time()

print('Execution Time: {}'.format(end-start))
2 tính bình phương của mỗi số trong danh sách và hàm
numbers = [2, 3, 5, 8]
start = time.time()
calc_square(numbers)
calc_cube(numbers)
end = time.time()

print('Execution Time: {}'.format(end-start))
3 tính lập phương của mỗi số trong danh sách. Câu lệnh
numbers = [2, 3, 5, 8]
start = time.time()
calc_square(numbers)
calc_cube(numbers)
end = time.time()

print('Execution Time: {}'.format(end-start))
6 trong phần thân của các hàm tạm dừng việc thực thi mã trong 0. 1 giây ở cuối mỗi lần lặp. Chúng tôi đã thêm câu lệnh này vào các chức năng để làm cho CPU không hoạt động trong giây lát và mô phỏng tác vụ liên kết I/O. Trong các tình huống thực tế, tác vụ liên kết I/O có thể đợi thiết bị ngoại vi hoặc phản hồi của dịch vụ web

numbers = [2, 3, 5, 8]
start = time.time()
calc_square(numbers)
calc_cube(numbers)
end = time.time()

print('Execution Time: {}'.format(end-start))

Như bạn đã thấy, việc thực hiện tuần tự chương trình mất gần một giây. Bây giờ, hãy sử dụng thời gian nhàn rỗi của CPU, sử dụng kỹ thuật đa luồng và giảm tổng thời gian thực hiện. Kỹ thuật đa luồng làm giảm thời gian chạy bằng cách phân bổ thời gian CPU cho một tác vụ trong khi các tác vụ khác đang chờ phản hồi I/O. Hãy xem nó hoạt động như thế nào

import threading

start = time.time()

square_thread = threading.Thread(target=calc_square, args=(numbers,))
cube_thread = threading.Thread(target=calc_cube, args=(numbers,))

square_thread.start()
cube_thread.start()

square_thread.join()
cube_thread.join()

end = time.time()

print('Execution Time: {}'.format(end-start))
    2 ^ 2 = 4

    2 ^ 3 = 8

    3 ^ 3 = 27

    3 ^ 2 = 9

    5 ^ 3 = 125
    5 ^ 2 = 25

    8 ^ 2 = 64
    8 ^ 3 = 512

    Execution Time: 0.4172379970550537

Tuyệt vời, thời gian thực hiện chưa đến nửa giây và đó là một cải tiến đáng kể nhờ đa luồng. Hãy khám phá từng dòng mã

Trước tiên, chúng ta cần nhập mô-đun `threading`, mô-đun phân luồng cấp cao với nhiều tính năng hữu ích khác nhau

Chúng tôi sử dụng phương thức xây dựng `Thread` để tạo một cá thể luồng. Trong ví dụ này, phương thức `Thread` nhận hai đầu vào, tên hàm (`mục tiêu`) và các đối số của nó (`args`), dưới dạng một bộ. Chức năng này là những gì sẽ được thực thi khi một luồng bắt đầu thực hiện. Khi chúng ta khởi tạo lớp `Thread`, phương thức xây dựng `Thread` sẽ được gọi tự động và nó sẽ tạo một luồng mới. Nhưng luồng mới sẽ không bắt đầu thực thi ngay lập tức, đây là một tính năng đồng bộ hóa có giá trị cho phép chúng tôi bắt đầu các luồng sau khi tất cả chúng đã được phân bổ

Để bắt đầu thực thi luồng, chúng ta cần gọi riêng phương thức `start` của từng đối tượng luồng. Vì vậy, hai dòng này thực hiện đồng thời các chủ đề hình vuông và khối lập phương

square_thread.start()
cube_thread.start()

Điều cuối cùng chúng ta cần làm là gọi phương thức `join`, phương thức này yêu cầu một luồng đợi cho đến khi quá trình thực thi của luồng kia hoàn tất

square_thread.join()
cube_thread.join()

Trong khi phương thức

numbers = [2, 3, 5, 8]
start = time.time()
calc_square(numbers)
calc_cube(numbers)
end = time.time()

print('Execution Time: {}'.format(end-start))
7 tạm dừng việc thực thi hàm
numbers = [2, 3, 5, 8]
start = time.time()
calc_square(numbers)
calc_cube(numbers)
end = time.time()

print('Execution Time: {}'.format(end-start))
2 cho 0. 1 giây, hàm
numbers = [2, 3, 5, 8]
start = time.time()
calc_square(numbers)
calc_cube(numbers)
end = time.time()

print('Execution Time: {}'.format(end-start))
3 được thực thi và in ra khối lập phương của một giá trị trong danh sách, sau đó nó chuyển sang chế độ ngủ và hàm
numbers = [2, 3, 5, 8]
start = time.time()
calc_square(numbers)
calc_cube(numbers)
end = time.time()

print('Execution Time: {}'.format(end-start))
2 sẽ được thực thi. Nói cách khác, hệ điều hành chuyển đổi qua lại giữa các luồng, chạy từng luồng một, dẫn đến cải thiện thời gian chạy của toàn bộ tiến trình.

Phương pháp threading

Mô-đun Python threading cung cấp một số chức năng hữu ích giúp bạn quản lý chương trình đa luồng của chúng tôi một cách hiệu quả

**Tên phương thức****Mô tả**Kết quả của phương thứcphân luồng. active_count()trả về số Chủ đề hiện đang hoạt động8phân luồng. current_thread()trả về Chủ đề hiện tại, tương ứng với chủ đề điều khiển của người gọi<_MainThread(MainThread, started 4303996288)>threading.enumerate()trả về danh sách tất cả các Chủ đề hiện đang hoạt động, bao gồm cả chủ đề chính; . main_thread()[<_MainThread(MainThread, started 4303996288)>,,,,, , ,]threading.main_thread()trả về luồng chính<_MainThread(MainThread, started 4303996288)>

Phần kết luận

Đa luồng là một khái niệm rộng trong lập trình nâng cao để triển khai các ứng dụng hiệu suất cao và hướng dẫn này đã đề cập đến những điều cơ bản về đa luồng trong Python. Chúng tôi đã thảo luận về thuật ngữ cơ bản của điện toán đồng thời và song song, sau đó triển khai một chương trình đa luồng cơ bản để tính bình phương và lập phương của một danh sách các số. Chúng ta sẽ thảo luận về một số kỹ thuật đa luồng nâng cao hơn trong tương lai

Data SciencepythonHướng dẫn

Là chủ đề số nguyên Python

Thông tin về các Tác giả

Mehdi Lotfinejad

Mehdi là Kỹ sư dữ liệu cao cấp và Trưởng nhóm tại ADA. Anh ấy là một huấn luyện viên chuyên nghiệp, người thích viết các hướng dẫn phân tích dữ liệu

Chủ đề trong Python là gì?

Các luồng trong python là một thực thể trong một quy trình có thể được lên lịch để thực thi . Nói một cách đơn giản hơn, luồng là một quá trình tính toán được thực hiện bởi máy tính. Đó là một chuỗi các hướng dẫn như vậy trong một chương trình có thể được thực thi độc lập với các mã khác.

Python có phải là một luồng không?

Python KHÔNG phải là ngôn ngữ đơn luồng . Các quy trình Python thường sử dụng một luồng đơn vì GIL. Bất chấp GIL, các thư viện thực hiện các tác vụ tính toán nặng như numpy, scipy và pytorch sử dụng các triển khai dựa trên C dưới mui xe, cho phép sử dụng nhiều lõi.

Python có đa luồng không?

Python không hỗ trợ đa luồng vì Python trên trình thông dịch Cpython không hỗ trợ thực thi đa lõi thực sự thông qua đa luồng. Tuy nhiên, Python không có thư viện luồng. GIL không ngăn luồng.

Là chủ đề số nguyên

Net tất cả các loại 32-bit (e. g, int , bool , v.v.) là luồng an toàn . Tức là sẽ không ghi một phần (theo thông số kỹ thuật).