/ / Cách chạy mã Python của bạn đồng thời bằng cách sử dụng chủ đề

Cách chạy mã Python của bạn đồng thời bằng cách sử dụng chủ đề

Thời gian thực hiện là một trong những thước đo phổ biến về hiệu quả của một chương trình. Thời gian thực hiện càng nhanh thì chương trình càng tốt. Phân luồng là một kỹ thuật cho phép một chương trình thực hiện đồng thời nhiều tác vụ hoặc quy trình.


Bạn sẽ học cách sử dụng Python tích hợp sẵn xâu chuỗi mô-đun và concurrent.features mô-đun. Cả hai mô-đun này đều cung cấp các cách đơn giản để tạo và quản lý chủ đề


Tầm quan trọng của luồng

Phân luồng làm giảm lượng thời gian mà một chương trình cần để hoàn thành một công việc. Nếu công việc chứa nhiều tác vụ độc lập, bạn có thể sử dụng phân luồng để chạy các tác vụ đồng thời, giảm thời gian chờ đợi của chương trình để hoàn thành một tác vụ trước khi chuyển sang tác vụ tiếp theo.

Ví dụ: một chương trình tải xuống nhiều tệp hình ảnh từ internet. Chương trình này có thể sử dụng phân luồng để tải xuống các tệp song song thay vì tải xuống từng tệp một. Điều này giúp loại bỏ thời gian chương trình phải đợi quá trình tải xuống một tệp hoàn tất trước khi chuyển sang tệp tiếp theo.

Chương trình ban đầu trước khi phân luồng

Hàm trong chương trình sau đại diện cho một nhiệm vụ. Nhiệm vụ là tạm dừng thực hiện chương trình trong một giây. Chương trình gọi hàm hai lần do đó tạo ra hai tác vụ. Sau đó, nó sẽ tính toán thời gian cần thiết để toàn bộ chương trình chạy và sau đó hiển thị nó trên màn hình.

 import time

start_time = time.perf_counter()

def pause():
    print('Sleeping 1 second...')
    time.sleep(1)
    print('Done Sleeping...')

pause()
pause()
finish_time = time.perf_counter()
print(f'Finished in {round(finish_time - start_time, 2)} second(s)')

Đầu ra cho thấy chương trình mất 2,01 giây để thực thi. Mỗi tác vụ mất một giây và phần còn lại của mã mất 0,01 giây để thực thi.

đầu ra của chương trình hiển thị thời gian chạy chương trình

Bạn có thể sử dụng luồng để thực hiện đồng thời cả hai tác vụ. Điều này sẽ mất cả hai nhiệm vụ một giây để thực hiện.

Triển khai phân luồng bằng cách sử dụng Mô-đun phân luồng

Để sửa đổi mã ban đầu để triển khai phân luồng, hãy nhập tệp xâu chuỗi mô-đun. Tạo hai chủ đề, chủ đề_1chủ đề_2 sử dụng Chủ đề lớp học. Gọi bắt đầu phương thức trên mỗi luồng để bắt đầu thực thi. Gọi tham gia trên mỗi luồng để đợi quá trình thực thi của chúng hoàn tất trước khi phần còn lại của chương trình thực thi.

 import time
import threading
start_time = time.perf_counter()

def pause():
    print('Sleeping 1 second...')
    time.sleep(1)
    print('Done Sleeping...')

thread_1 = threading.Thread(target=pause)
thread_2 = threading.Thread(target=pause)

thread_1.start()
thread_2.start()

thread_1.join()
thread_2.join()

finish_time = time.perf_counter()
print(f'Finished in {round(finish_time - start_time, 2)} second(s)')

Chương trình sẽ chạy đồng thời cả hai chủ đề. Điều này sẽ giảm lượng thời gian cần thiết để hoàn thành cả hai nhiệm vụ.

đầu ra của chương trình hiển thị thời gian chạy chương trình

Đầu ra cho thấy thời gian để chạy các tác vụ tương tự là khoảng một giây. Đây là một nửa thời gian của chương trình ban đầu.

Triển khai phân luồng bằng Mô-đun concurrent.futures

Python 3.2 chứng kiến ​​sự ra đời của concurrent.futures mô-đun. Mô-đun này cung cấp giao diện cấp cao để thực hiện các tác vụ không đồng bộ bằng các luồng. Nó cung cấp một cách đơn giản hơn để thực hiện các tác vụ song song.

Để sửa đổi chương trình ban đầu để sử dụng phân luồng, hãy nhập mô-đun concurrent.features. Sử dụng ThreadPoolExecutor lớp từ mô-đun concurrent.futures để tạo một nhóm chủ đề. Nộp tạm ngừng hoạt động với hồ bơi hai lần. Các nộp phương thức trả về một tương lai đối tượng đại diện cho kết quả của lời gọi hàm.

Lặp đi lặp lại tương lai và in kết quả của họ bằng cách sử dụng kết quả phương pháp.

 import time
import concurrent.futures

start_time = time.perf_counter()

def pause():
    print('Sleeping 1 second...')
    time.sleep(1)
    return 'Done Sleeping...'

with concurrent.futures.ThreadPoolExecutor() as executor:
    results = [executor.submit(pause) for _ in range(2)]
    for f in concurrent.futures.as_completed(results):
        print(f.result())

finish_time = time.perf_counter()

print(f'Finished in {round(finish_time - start_time, 2)} second(s)')

Mô-đun concurrent.features đảm nhận việc bắt đầu và tham gia chuỗi cho bạn. Điều này làm cho mã của bạn sạch hơn.

đầu ra của chương trình hiển thị thời gian chạy chương trình

Đầu ra giống với đầu ra của mô-đun phân luồng. Mô-đun phân luồng hữu ích cho các trường hợp đơn giản khi bạn cần chạy song song một vài luồng. Mặt khác, mô-đun concurrent.futures hữu ích cho các trường hợp phức tạp hơn khi bạn cần chạy nhiều tác vụ đồng thời.

Sử dụng phân luồng trong một kịch bản trong thế giới thực

Sử dụng các luồng để chạy chương trình trên đã giảm thời gian xuống một giây. Trong thế giới thực, chủ đề tiết kiệm thời gian hơn. Tạo một chương trình tải hình ảnh từ internet. Bắt đầu bằng cách tạo một môi trường ảo mới. Chạy lệnh sau trong terminal để cài đặt yêu cầu thư viện:

 pip install requests 

Thư viện yêu cầu sẽ cho phép bạn gửi các yêu cầu HTTP. Nhập thư viện yêu cầu và thư viện thời gian.

 import requests
import time

Tạo danh sách URL của hình ảnh bạn muốn tải xuống. Hãy để chúng ít nhất là mười để bạn có thể nhận thấy sự khác biệt đáng kể khi triển khai phân luồng.

 img_urls = [
    'https://images.unsplash.com/photo-1524429656589-6633a470097c',
    'https://images.unsplash.com/photo-1530224264768-7ff8c1789d79',
    'https://images.unsplash.com/photo-1564135624576-c5c88640f235',
    'https://images.unsplash.com/photo-1541698444083-023c97d3f4b6',
    'https://images.unsplash.com/photo-1522364723953-452d3431c267',
    'https://images.unsplash.com/photo-1513938709626-033611b8cc03',
    'https://images.unsplash.com/photo-1507143550189-fed454f93097',
    'https://images.unsplash.com/photo-1493976040374-85c8e12f0c0e',
    'https://images.unsplash.com/photo-1504198453319-5ce911bafcde',
    'https://images.unsplash.com/photo-1530122037265-a5f1f91d3b99',
    'https://images.unsplash.com/photo-1516972810927-80185027ca84',
    'https://images.unsplash.com/photo-1550439062-609e1531270e',
]

Lặp lại danh sách các URL tải xuống từng hình ảnh vào cùng một thư mục chứa dự án của bạn. Hiển thị thời gian cần thiết để tải xuống các hình ảnh bằng cách trừ đi thời gian kết thúc từ thời gian bắt đầu.

 start_time = time.perf_counter()
for img_url in img_urls:
    img_bytes = requests.get(img_url).content
    img_name = img_url.split("https://www.smartreviewaz.com/")[3]
    img_name = f'{img_name}.jpg'
    with open(img_name, 'wb') as img_file:
        img_file.write(img_bytes)
        print(f'{img_name} was downloaded...')
finish_time = time.perf_counter()
print(f'Finished in {finish_time - start_time} seconds')

Chương trình mất khoảng 22 giây để tải xuống 12 hình ảnh. Nó có thể thay đổi đối với bạn vì thời gian tải xuống hình ảnh cũng phụ thuộc vào tốc độ internet của bạn.

đầu ra của chương trình hiển thị thời gian tải hình ảnh xuống

Sửa đổi chương trình để sử dụng phân luồng bằng mô-đun concurrent.features. Thay vì một vòng lặp, hãy sử dụng một chức năng. Đây là chức năng bạn sẽ chuyển đến người thừa hành ví dụ.

 import requests
import time
import concurrent.futures

img_urls = [
    'https://images.unsplash.com/photo-1524429656589-6633a470097c',
    'https://images.unsplash.com/photo-1530224264768-7ff8c1789d79',
    'https://images.unsplash.com/photo-1564135624576-c5c88640f235',
    'https://images.unsplash.com/photo-1541698444083-023c97d3f4b6',
    'https://images.unsplash.com/photo-1522364723953-452d3431c267',
    'https://images.unsplash.com/photo-1513938709626-033611b8cc03',
    'https://images.unsplash.com/photo-1507143550189-fed454f93097',
    'https://images.unsplash.com/photo-1493976040374-85c8e12f0c0e',
    'https://images.unsplash.com/photo-1504198453319-5ce911bafcde',
    'https://images.unsplash.com/photo-1530122037265-a5f1f91d3b99',
    'https://images.unsplash.com/photo-1516972810927-80185027ca84',
    'https://images.unsplash.com/photo-1550439062-609e1531270e',
]

start_time = time.perf_counter()

def download_image(img_url):
    img_bytes = requests.get(img_url).content
    img_name = img_url.split("https://www.smartreviewaz.com/")[3]
    img_name = f'{img_name}.jpg'
    with open(img_name, 'wb') as img_file:
        img_file.write(img_bytes)
        print(f'{img_name} was downloaded...')

with concurrent.futures.ThreadPoolExecutor() as executor:
    executor.map(download_image, img_urls)

finish_time = time.perf_counter()

print(f'Finished in {finish_time-start_time} seconds')

Sau khi giới thiệu luồng. Thời gian giảm đáng kể. Chỉ mất 4 giây để hoàn thành việc thực hiện chương trình.

đầu ra của chương trình hiển thị thời gian tải hình ảnh xuống

Các kịch bản phù hợp cho Threading

Một số tình huống phù hợp để phân luồng là:

  • Nhiệm vụ ràng buộc I/O: Nếu chương trình dành phần lớn thời gian để chờ các thao tác nhập hoặc xuất hoàn tất. Phân luồng có thể cải thiện hiệu suất bằng cách cho phép các tác vụ khác thực thi trong khi chờ các thao tác I/O hoàn tất.
  • rút trích nội dung trang web: Quét web liên quan đến việc thực hiện các yêu cầu HTTP và phân tích cú pháp các phản hồi HTML. Phân luồng giúp tăng tốc quá trình bằng cách cho phép bạn thực hiện đồng thời nhiều yêu cầu.
  • Các tác vụ liên quan đến CPU: Phân luồng có thể giúp cải thiện hiệu suất bằng cách cho phép nhiều tác vụ thực thi song song.

Tự làm quen với phân luồng bằng các ngôn ngữ khác

Python không phải là ngôn ngữ duy nhất hỗ trợ luồng. Hầu hết các ngôn ngữ lập trình đều hỗ trợ một số dạng phân luồng. Điều quan trọng là bạn phải tự làm quen với việc triển khai các chuỗi trong các ngôn ngữ khác. Điều này trang bị cho bạn những kỹ năng cần thiết để giải quyết các tình huống khác nhau khi có thể áp dụng phân luồng.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *