Khóa học python

Thread Priority trong Python

0 phút đọc

Trong lập trình đa luồng (multithreading), việc quản lý ưu tiên của các thread có thể giúp tối ưu hóa hiệu suất của ứng dụng, đặc biệt là khi các thread có mức độ quan trọng khác nhau. Tuy nhiên, trong Python, việc điều chỉnh ưu tiên của các thread không phải là một nhiệm vụ đơn giản do các hạn chế của Global Interpreter Lock (GIL). Bài viết này sẽ cung cấp một hướng dẫn chi tiết về cách quản lý ưu tiên của các thread trong Python, kèm theo các ví dụ minh họa cụ thể.

Đa Luồng và GIL trong Python

Python sử dụng Global Interpreter Lock (GIL) để quản lý việc thực thi các thread. GIL đảm bảo rằng chỉ có một thread được thực thi tại một thời điểm, ngay cả trên các hệ thống đa lõi. Điều này có nghĩa là việc điều chỉnh ưu tiên của các thread trong Python không thể thực hiện một cách trực tiếp như trong một số ngôn ngữ lập trình khác.

Tạo và Bắt Đầu Một Thread

Để tạo một thread mới trong Python, bạn cần sử dụng lớp Thread từ module threading. Dưới đây là một ví dụ đơn giản về cách tạo và bắt đầu một thread:

python Copy
import threading
import time

def print_numbers():
    for i in range(5):
        print(i)
        time.sleep(1)

# Tạo một thread mới
thread = threading.Thread(target=print_numbers)

# Bắt đầu thread
thread.start()

# Chờ thread hoàn thành
thread.join()

Trong ví dụ trên, chúng ta đã tạo một thread mới để thực thi hàm print_numbers. Thread này sẽ in ra các số từ 0 đến 4, mỗi số cách nhau 1 giây. Hàm join được sử dụng để chờ thread hoàn thành trước khi tiếp tục thực thi các lệnh tiếp theo trong chương trình chính.

Điều Chỉnh Ưu Tiên của Thread

Sử Dụng nice trong UNIX

Trên các hệ điều hành UNIX, bạn có thể sử dụng lệnh nice để điều chỉnh mức độ ưu tiên của một tiến trình. Mức độ ưu tiên càng cao thì giá trị nice càng thấp. Bạn có thể sử dụng lệnh nice khi chạy script Python để điều chỉnh ưu tiên của toàn bộ tiến trình, bao gồm tất cả các thread trong tiến trình đó.

Ví dụ:

bash Copy
nice -n 10 python myscript.py

Trong ví dụ này, script myscript.py sẽ được chạy với mức độ ưu tiên 10.

Sử Dụng psutil trong Windows

Trên Windows, bạn có thể sử dụng module psutil để điều chỉnh mức độ ưu tiên của một tiến trình. Dưới đây là một ví dụ về cách sử dụng psutil để đặt mức độ ưu tiên cho một tiến trình:

python Copy
import psutil
import os

# Lấy ID của tiến trình hiện tại
pid = os.getpid()

# Tạo đối tượng Process
p = psutil.Process(pid)

# Đặt mức độ ưu tiên
p.nice(psutil.HIGH_PRIORITY_CLASS)

Trong ví dụ này, chúng ta đã đặt mức độ ưu tiên cao cho tiến trình hiện tại.

Ví Dụ về Điều Chỉnh Ưu Tiên của Thread

Sử Dụng ctypes trong Windows

Trên Windows, bạn có thể sử dụng module ctypes để điều chỉnh mức độ ưu tiên của các thread. Dưới đây là một ví dụ về cách sử dụng ctypes để đặt mức độ ưu tiên cho một thread:

python Copy
import threading
import ctypes
import time

# Định nghĩa các hằng số
THREAD_SET_INFORMATION = 0x20
THREAD_PRIORITY_ABOVE_NORMAL = 1

# Tạo lớp DummyThread kế thừa từ threading.Thread
class DummyThread(threading.Thread):
    def __init__(self, begin, name, iterations):
        threading.Thread.__init__(self)
        self.begin = begin
        self.tid = None
        self.iterations = iterations
        self.setName(name)

    def setPriority(self, priority):
        if not self.isAlive():
            print('Unable to set priority of stopped thread')
            return
        handle = ctypes.windll.kernel32.OpenThread(THREAD_SET_INFORMATION, False, self.tid)
        result = ctypes.windll.kernel32.SetThreadPriority(handle, priority)
        ctypes.windll.kernel32.CloseHandle(handle)
        if not result:
            print('Failed to set priority of thread', ctypes.windll.kernel32.GetLastError())

    def run(self):
        self.tid = ctypes.windll.kernel32.GetCurrentThreadId()
        name = self.getName()
        self.begin.wait()
        while self.iterations:
            print(name, 'running')
            start = time.time()
            while time.time() - start < 1:
                pass
            self.iterations -= 1

if __name__ == "__main__":
    start = threading.Event()
    normal = DummyThread(start, 'normal', 10)
    high = DummyThread(start, 'high', 10)

    normal.start()
    high.start()

    high.setPriority(THREAD_PRIORITY_ABOVE_NORMAL)

    start.set()

    normal.join()
    high.join()

Trong ví dụ này, chúng ta đã tạo hai thread normalhigh. Thread high được đặt mức độ ưu tiên cao hơn bằng cách sử dụng ctypes.

Sử Dụng Priority Queue trong Python

Một cách khác để quản lý ưu tiên của các tác vụ trong Python là sử dụng Priority Queue. Priority Queue là một cấu trúc dữ liệu cho phép các mục được xử lý theo thứ tự ưu tiên của chúng.

Tạo Priority Queue

Python cung cấp lớp PriorityQueue trong module queue để tạo một hàng đợi ưu tiên an toàn cho thread. Dưới đây là một ví dụ về cách sử dụng PriorityQueue:

python Copy
import queue
import threading
import time

# Tạo lớp ThreadSafePriorityQueue
class ThreadSafePriorityQueue:
    def __init__(self):
        self._queue = queue.PriorityQueue()
        self._lock = threading.Lock()

    def put(self, item, priority):
        with self._lock:
            self._queue.put((priority, item))

    def get(self):
        with self._lock:
            if not self._queue.empty():
                priority, item = self._queue.get()
                return item
            else:
                return None

# Hàm producer để thêm các mục vào hàng đợi
def producer(q):
    for i in range(5):
        q.put(i, i)
        time.sleep(1)
    q.put(None, None)

# Hàm consumer để lấy các mục từ hàng đợi
def consumer(q):
    while True:
        item = q.get()
        if item is None:
            break
        print("Consumed:", item)

if __name__ == "__main__":
    q = ThreadSafePriorityQueue()

    producer_thread = threading.Thread(target=producer, args=(q,))
    consumer_thread = threading.Thread(target=consumer, args=(q,))

    producer_thread.start()
    consumer_thread.start()

    producer_thread.join()
    consumer_thread.join()

Trong ví dụ này, chúng ta đã tạo một hàng đợi ưu tiên an toàn cho thread và sử dụng hai thread producerconsumer để thêm và lấy các mục từ hàng đợi.

Các Lỗi Thường Gặp Khi Điều Chỉnh Ưu Tiên của Thread

Lỗi Khi Gọi join Trên Thread Chính

Gọi join trên thread chính sẽ gây ra lỗi RuntimeError vì điều này sẽ dẫn đến deadlock. Ví dụ:

python Copy
import threading

def task():
    print("Task is running")

# Gọi join trên thread chính
threading.current_thread().join()

Lỗi Khi Gọi join Trước Khi Bắt Đầu Thread

Gọi join trên một thread trước khi nó được bắt đầu cũng sẽ gây ra lỗi RuntimeError. Ví dụ:

python Copy
import threading

def task():
    print("Task is running")

# Tạo thread nhưng không bắt đầu
thread = threading.Thread(target=task)

# Gọi join trước khi bắt đầu thread
thread.join()

Kết Luận

Việc điều chỉnh ưu tiên của các thread trong Python có thể gặp nhiều thách thức do các hạn chế của GIL. Tuy nhiên, bằng cách sử dụng các công cụ và kỹ thuật như nice trên UNIX, psutil trên Windows, và Priority Queue, bạn có thể quản lý ưu tiên của các tác vụ một cách hiệu quả. Hy vọng rằng bài viết này đã cung cấp cho bạn một cái nhìn toàn diện về cách quản lý ưu tiên của các thread trong Python. Hãy thử áp dụng những kiến thức này vào các dự án của bạn để cải thiện hiệu suất và khả năng quản lý của ứng dụng.

Avatar
Được viết bởi

Admin Team

Gợi ý câu hỏi phỏng vấn

Không có dữ liệu

Không có dữ liệu

Gợi ý bài viết
Không có dữ liệu

Không có dữ liệu

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào