PYTHON CONCURRENCY
CÁC CHỦ ĐỀ
BÀI MỚI NHẤT
MỚI CẬP NHẬT

Thông báo: Download 4 khóa học Python từ cơ bản đến nâng cao tại đây.

Cách sử dụng module threading trong Python

Việc tối ưu hóa hiệu suất và sử dụng tài nguyên một cách hiệu quả là vô cùng quan trọng. Một trong những cách để đạt được điều này là sử dụng đa luồng. Trong Python, module threading cung cấp các công cụ mạnh mẽ để tạo và quản lý các luồng, giúp các ứng dụng của bạn chạy mượt mà và nhanh chóng hơn, đặc biệt là đối với các tác vụ I/O-bound. Hướng dẫn này sẽ giúp bạn hiểu rõ hơn về cách sử dụng module threading trong Python để phát triển các ứng dụng đa luồng, từ đó nâng cao hiệu suất và khả năng xử lý của chương trình.

test php

banquyen png
Bài viết này được đăng tại freetuts.net, không được copy dưới mọi hình thức.

Ứng dụng đơn luồng trong Python

Hãy bắt đầu với một chương trình đơn giản:

from time import sleep, perf_counter

def task():
    print('Starting a task...')
    sleep(1)
    print('done')

start_time = perf_counter()

task()
task()

end_time = perf_counter()

print(f'It took {end_time- start_time: 0.2f} second(s) to complete.')

Cách hoạt động của chương trình:

Đầu tiên, import các hàm sleep()perf_counter() từ module time:

Bài viết này được đăng tại [free tuts .net]

from time import sleep, perf_counter

Thứ hai, định nghĩa một hàm mất 1 giây để hoàn thành:

def task():
    print('Starting a task...')
    sleep(1)
    print('done')

Thứ ba, lấy giá trị của bộ đếm hiệu năng bằng cách gọi hàm perf_counter():

start_time = perf_counter()

Thứ tư, gọi hàm task() hai lần:

task()
task()

Thứ năm, lấy giá trị của bộ đếm hiệu năng bằng cách gọi hàm perf_counter():

end_time = perf_counter()

Cuối cùng, hiển thị thời gian hoàn thành của việc chạy hàm task() hai lần:

print(f'It took {end_time- start_time: 0.2f} second(s) to complete.')

Dưới đây là kết quả:

Starting a task...
done
Starting a task...
done
It took  2.00 second(s) to complete.

Chương trình mất khoảng hai giây để hoàn thành. Nếu bạn gọi hàm task() 10 lần, nó sẽ mất khoảng 10 giây để hoàn thành.

Python Closure Example png

Chương trình này có một tiến trình với một luồng duy nhất, gọi là luồng chính (main thread). Vì chương trình chỉ có một luồng, nó được gọi là chương trình đơn luồng.

Sử dụng threading để phát triển chương trình đa luồng Python

Để tạo một chương trình đa luồng, bạn cần sử dụng module threading trong Python.

Đầu tiên, import lớp Thread từ module threading:

from threading import Thread

Thứ hai, tạo một luồng mới bằng cách khởi tạo một đối tượng Thread:

new_thread = Thread(target=fn, args=args_tuple)

Thread() chấp nhận nhiều tham số. Những tham số chính là:

  • target: xác định hàm (fn) để chạy trong luồng mới.
  • args: xác định các tham số của hàm (fn). args là một tuple.

Thứ ba, khởi động luồng bằng cách gọi phương thức start() của đối tượng Thread:

new_thread.start()

Nếu bạn muốn chờ luồng hoàn thành trong luồng chính, bạn có thể gọi phương thức join():

new_thread.join()

Bằng cách gọi phương thức join(), luồng chính sẽ chờ luồng con hoàn thành trước khi nó kết thúc.

Dưới đây là chương trình minh họa cách sử dụng module threading:

from time import sleep, perf_counter
from threading import Thread

def task():
    print('Starting a task...')
    sleep(1)
    print('done')

start_time = perf_counter()

# tạo hai luồng mới
t1 = Thread(target=task)
t2 = Thread(target=task)

# khởi động các luồng
t1.start()
t2.start()

# chờ các luồng hoàn thành
t1.join()
t2.join()

end_time = perf_counter()

print(f'It took {end_time- start_time: 0.2f} second(s) to complete.')

Cách hoạt động của chương trình:

Tạo hai luồng mới:

t1 = Thread(target=task)
t2 = Thread(target=task)

Khởi động cả hai luồng bằng cách gọi phương thức start():

t1.start()
t2.start()

Chờ cả hai luồng hoàn thành bằng cách gọi phương thức join():

t1.join()
t2.join()

Cuối cùng, hiển thị thời gian thực thi:

print(f'It took {end_time- start_time: 0.2f} second(s) to complete.')

Kết quả:

Starting a task...
Starting a task...
done
done
It took  1.00 second(s) to complete.

Chương trình sẽ có ba luồng: luồng chính và hai luồng con khác. Từ kết quả, chương trình mất một giây thay vì hai giây để hoàn thành.

Python Threading Multi threaded App png

Truyền tham số cho các luồng trong Python

Chương trình sau đây minh họa cách truyền tham số cho hàm được gán cho một luồng:

from time import sleep, perf_counter
from threading import Thread

def task(id):
    print(f'Starting the task {id}...')
    sleep(1)
    print(f'The task {id} completed')

start_time = perf_counter()

# tạo và khởi động 10 luồng
threads = []
for n in range(1, 11):
    t = Thread(target=task, args=(n,))
    threads.append(t)
    t.start()

# chờ các luồng hoàn thành
for t in threads:
    t.join()

end_time = perf_counter()

print(f'It took {end_time- start_time: 0.2f} second(s) to complete.')

Cách hoạt động của chương trình:

Định nghĩa một hàm task() nhận một tham số:

def task(id):
    print(f'Starting the task {id}...')
    sleep(1)
    print(f'The task {id} completed')

Tạo 10 luồng mới và truyền một id cho mỗi luồng. Danh sách threads được sử dụng để theo dõi tất cả các luồng mới tạo:

threads = []
for n in range(1, 11):
    t = Thread(target=task, args=(n,))
    threads.append(t)
    t.start()

Chờ tất cả các luồng hoàn thành bằng cách gọi phương thức join():

for t in threads:
    t.join()

Kết quả:

Starting the task 1...
Starting the task 2...
Starting the task 3...
Starting the task 4...
Starting the task 5...
Starting the task 6...
Starting the task 7...
Starting the task 8...
Starting the task 9...
Starting the task 10...
The task 10 completed
The task 8 completed
The task 1 completed
The task 6 completed
The task 7 completed
The task 9 completed
The task 3 completed
The task 4 completed
The task 2 completed
The task 5 completed
It took  1.02 second(s) to complete.

Chương trình chỉ mất khoảng 1,02 giây để hoàn thành. Lưu ý rằng chương trình không thực thi các luồng theo thứ tự từ 1 đến 10.

Khi nào nên sử dụng threading trong Python?

Như đã giới thiệu trong hướng dẫn về tiến trình và luồng, có hai loại tác vụ chính:

  • Tác vụ I/O-bound: thời gian dành cho I/O nhiều hơn đáng kể so với thời gian dành cho tính toán.
  • Tác vụ CPU-bound: thời gian dành cho tính toán nhiều hơn đáng kể so với thời gian chờ I/O.

Threading trong Python được tối ưu hóa cho các tác vụ I/O-bound. Ví dụ, yêu cầu tài nguyên từ xa, kết nối máy chủ cơ sở dữ liệu hoặc đọc và ghi file.

Ví dụ thực tế về threading trong Python

Giả sử bạn có một danh sách các file văn bản trong một thư mục, ví dụ: C:/temp/. Và bạn muốn thay thế một đoạn văn bản bằng một đoạn mới trong tất cả các file.

Chương trình đơn luồng dưới đây cho thấy cách thay thế một chuỗi con bằng chuỗi mới trong các file văn bản:

from time import perf_counter

def replace(filename, substr, new_substr):
    print(f'Processing the file {filename}')
    # đọc nội dung file
    with open(filename, 'r') as f:
        content = f.read()

    # thay thế chuỗi con
    content = content.replace(substr, new_substr)

    # ghi dữ liệu vào file
    with open(filename, 'w') as f:
        f.write(content)

def main():
    filenames = [
        'c:/temp/test1.txt',
        'c:/temp/test2.txt',
        'c:/temp/test3.txt',
        'c:/temp/test4.txt',
        'c:/temp/test5.txt',
        'c:/temp/test6.txt',
        'c:/temp/test7.txt',
        'c:/temp/test8.txt',
        'c:/temp/test9.txt',
        'c:/temp/test10.txt',
    ]

    for filename in filenames:
        replace(filename, 'ids', 'id')

if __name__ == "__main__":
    start_time = perf_counter()

    main()

    end_time = perf_counter()
    print(f'It took {end_time- start_time :0.2f} second(s) to complete.')

Kết quả:

It took 0.16 second(s) to complete.

Chương trình đa luồng có cùng chức năng như sau:

from threading import Thread
from time import perf_counter

def replace(filename, substr, new_substr):
    print(f'Processing the file {filename}')
    # đọc nội dung file
    with open(filename, 'r') as f:
        content = f.read()

    # thay thế chuỗi con
    content = content.replace(substr, new_substr)

    # ghi dữ liệu vào file
    with open(filename, 'w') as f:
        f.write(content)

def main():
    filenames = [
        'c:/temp/test1.txt',
        'c:/temp/test2.txt',
        'c:/temp/test3.txt',
        'c:/temp/test4.txt',
        'c:/temp/test5.txt',
        'c:/temp/test6.txt',
        'c:/temp/test7.txt',
        'c:/temp/test8.txt',
        'c:/temp/test9.txt',
        'c:/temp/test10.txt',
    ]

    # tạo các luồng
    threads = [Thread(target=replace, args=(filename, 'id', 'ids'))
               for filename in filenames]

    # khởi động các luồng
    for thread in threads:
        thread.start()

    # chờ các luồng hoàn thành
    for thread in threads:
        thread.join()

if __name__ == "__main__":
    start_time = perf_counter()

    main()

    end_time = perf_counter()
    print(f'It took {end_time- start_time :0.2f} second(s) to complete.')

Kết quả:

Processing the file c:/temp/test1.txt
Processing the file c:/temp/test2.txt
Processing the file c:/temp/test3.txt
Processing the file c:/temp/test4.txt
Processing the file c:/temp/test5.txt
Processing the file c:/temp/test6.txt
Processing the file c:/temp/test7.txt
Processing the file c:/temp/test8.txt
Processing the file c:/temp/test9.txt
Processing the file c:/temp/test10.txt
It took 0.02 second(s) to complete.

Chương trình đa luồng chạy nhanh hơn nhiều.

Kết bài

Việc sử dụng module threading trong Python mang lại nhiều lợi ích đáng kể khi phát triển các ứng dụng đa luồng, đặc biệt là trong các tác vụ I/O-bound. Bằng cách tạo các luồng mới thông qua Thread(function, args), khởi động chúng bằng phương thức start(), và chờ đợi chúng hoàn thành với phương thức join(), bạn có thể tối ưu hóa hiệu suất và sử dụng tài nguyên hệ thống một cách hiệu quả hơn. Tuy nhiên, cần lưu ý rằng đa luồng chỉ thực sự hữu ích với các tác vụ I/O-bound, vì các tác vụ CPU-bound thường không mang lại lợi ích tương tự do những hạn chế của GIL (Global Interpreter Lock) trong Python. Hy vọng rằng qua hướng dẫn này, bạn đã nắm bắt được cách sử dụng threading để phát triển các ứng dụng đa luồng trong Python, giúp tối ưu hóa và cải thiện hiệu suất chương trình của mình.

Cùng chuyên mục:

Hướng dẫn xây dựng Command-Line Interface (CLI) bằng Quo trong Python

Hướng dẫn xây dựng Command-Line Interface (CLI) bằng Quo trong Python

Hướng dẫn toàn diện về module datetime trong Python

Hướng dẫn toàn diện về module datetime trong Python

Cách truy cập và thiết lập biến môi trường trong Python

Cách truy cập và thiết lập biến môi trường trong Python

Lớp dữ liệu (Data Classes) trong Python với decorator @dataclass

Lớp dữ liệu (Data Classes) trong Python với decorator @dataclass

Từ khóa yield trong Python

Từ khóa yield trong Python

Sự khác biệt giữa sort() và sorted() trong Python

Sự khác biệt giữa sort() và sorted() trong Python

Sử dụng Poetry để quản lý dependencies trong Python

Sử dụng Poetry để quản lý dependencies trong Python

Định dạng chuỗi Strings trong Python

Định dạng chuỗi Strings trong Python

Một tác vụ phổ biến khi làm việc với danh sách trong Python

Một tác vụ phổ biến khi làm việc với danh sách trong Python

Làm việc với các biến môi trường trong Python

Làm việc với các biến môi trường trong Python

Sự khác biệt giữa set() và frozenset() trong Python

Sự khác biệt giữa set() và frozenset() trong Python

Sự khác biệt giữa iterator và iterable trong Python

Sự khác biệt giữa iterator và iterable trong Python

Cách làm việc với file tarball/tar trong Python

Cách làm việc với file tarball/tar trong Python

Chuyển đổi kiểu dữ liệu trong Python

Chuyển đổi kiểu dữ liệu trong Python

Sự khác biệt giữa toán tử == và is trong Python

Sự khác biệt giữa toán tử == và is trong Python

Làm việc với file ZIP trong Python

Làm việc với file ZIP trong Python

Cách sử dụng ThreadPoolExecutor trong Python

Cách sử dụng ThreadPoolExecutor trong Python

Sự khác biệt giữa byte objects và string trong Python

Sự khác biệt giữa byte objects và string trong Python

Xử lý độ chính xác các hàm floor, ceil, round, trunc, format  trong Python

Xử lý độ chính xác các hàm floor, ceil, round, trunc, format trong Python

Cách lặp qua nhiều list với hàm zip() trong Python

Cách lặp qua nhiều list với hàm zip() trong Python

Top