Đa luồng (Multithread) trong Python

Một chương trình đa luồng chứa hai hoặc nhiều phần mà có thể chạy đồng thời và mỗi phần có thể xử lý tác vụ khác nhau tại cùng một thời điểm, để sử dụng tốt nhất các nguồn có sẵn, đặc biệt khi máy tính của bạn có nhiều CPU.

Python cung cấp thread Module và threading Module để bạn có thể bắt đầu một thread mới cũng như một số tác vụ khác trong khi lập trình đa luồng. Mỗi một Thread đều có vòng đời chung là bắt đầu, chạy và kết thúc. Một Thread có thể bị ngắt (interrupt), hoặc tạm thời bị dừng (sleeping) trong khi các Thread khác đang chạy – được gọi là yielding.

Bắt đầu một Thread mới trong Python

Phương thức dưới đây có sẵn trong thread Module được sử dụng để bắt đầu một Thread mới:

thread.start_new_thread ( function, args[, kwargs] )

Lời gọi phương thức này được trả về ngay lập tức và Thread con bắt đầu và gọi hàm function với danh sách các tham số args đã truyền. Khi hàm function trả về, thì Thread kết thúc.

Ở đây, args là một Tuple của các tham số, sử dụng một Tuple trống để gọi hàm function mà không truyền cho nó bất kỳ tham số nào. Tham số kwargs là một Dictionary của các tham số từ khóa tùy ý. (bạn thao khảo chương Hàm trong Python để biết chi tiết tham số từ khóa là gì)

Ví dụ

 import thread

import time# Dinh nghia mot ham cho thread

def print_time( threadName, delay):

   count = 0

   while count < 5:

      time.sleep(delay)

      count += 1

      print "%s: %s" % ( threadName, time.ctime(time.time()) )# Tao hai thread nhu sau

try:

   thread.start_new_thread( print_time, ("Thread-1", 2, ) )

   thread.start_new_thread( print_time, ("Thread-2", 4, ) )

except:

   print "Error: khong the bat dau thread"while 1:

   pass

Kết quả là:

Thread-1: Mon Nov 21 15:42:17 2015

Thread-1: Mon Nov 21 15:42:19 2015

Thread-2: Mon Nov 21 15:42:19 2015

Thread-1: Mon Nov 21 15:42:21 2015

Thread-2: Mon Nov 21 15:42:23 2015

Thread-1: Mon Nov 21 15:42:23 2015

Thread-1: Mon Nov 21 15:42:25 2015

Thread-2: Mon Nov 21 15:42:27 2015

Thread-2: Mon Nov 21 15:42:31 2015

Thread-2: Mon Nov 21 15:42:35 2015

Mặc dù thread Module rất hiệu quả với đa luồng tầm thấp nhưng khi so sánh với threading Module thì nó có nhiều điểm hạn chế. Phần tiếp theo giới thiệu về threading Module.

threading Module trong Python

Module mới này được bao với Python 2.4 nhằm cung cấp nhiều hỗ trợ mạnh mẽ và cấp độ cao hơn cho các Thread trong khi so sánh với thread Module ở trên. Ngoài các phương thức có trong thread Module, thì threading Module còn bổ sung thêm một số phương thức khác, đó là:

  • threading.activeCount(): Trả về số đối tượng thread mà là active.
  • threading.currentThread(): Trả về số đối tượng thread trong Thread control của Caller.
  • threading.enumerate(): Trả về một danh sách tất cả đối tượng thread mà hiện tại là active.

Bên cạnh đó, threading Module có lớp Thread để triển khai đa luồng. Lớp này có các phương thức sau:

  • run(): Là entry point cho một Thread.
  • start(): Bắt đầu một thread bởi gọi phương thức run().
  • join([time]): Đợi cho các thread kết thúc.
  • isAlive(): Kiểm tra xem một thread có đang thực thi hay không.
  • getName(): Trả về tên của một thread.
  • setName(): Thiết lập tên của một thread.

Tạo Thread bởi sử dụng threading Module trong Python

Để triển khai một thread mới bởi sử dụng threading Module, bạn phải thực hiện:

  • Định nghĩa một lớp con của lớp Thread.
  • Ghi đè phương thức __init__(self [,args]) để bổ sung thêm các tham số.
  • Sau đó, ghi đè phương thức run(self [,args]) để triển khai những gì thread cần thực hiện khi được bắt đầu.

Một khi bạn đã tạo lớp con Thread mới, bạn có thể tạo một instance của nó và sau đó bắt đầu một Thread bởi triệu hồi phương thức start().

Ví dụ

 import threading

import timeexitFlag = 0class myThread (threading.Thread):

    def __init__(self, threadID, name, counter):

        threading.Thread.__init__(self)

        self.threadID = threadID

        self.name = name

        self.counter = counter

    def run(self):

        print "Bat dau " + self.name

        print_time(self.name, self.counter, 5)

        print "Ket thuc " + self.namedef print_time(threadName, delay, counter):

    while counter:

        if exitFlag:

            threadName.exit()

        time.sleep(delay)

        print "%s: %s" % (threadName, time.ctime(time.time()))

        counter -= 1# Tao cac thread moi

thread1 = myThread(1, "Thread-1", 1)

thread2 = myThread(2, "Thread-2", 2)# Bat dau cac thread moi

thread1.start()

thread2.start()print "Ket thuc Main Thread"

Kết quả là:

Bat dau Thread-1

Bat dau Thread-2

Ket thuc Main Thread

Thread-1: Mon Nov 21 09:10:03 2015

Thread-1: Mon Nov 21 09:10:04 2015

Thread-2: Mon Nov 21 09:10:04 2015

Thread-1: Mon Nov 21 09:10:05 2015

Thread-1: Mon Nov 21 09:10:06 2015

Thread-2: Mon Nov 21 09:10:06 2015

Thread-1: Mon Nov 21 09:10:07 2015

Ket thuc Thread-1

Thread-2: Mon Nov 21 09:10:08 2015

Thread-2: Mon Nov 21 09:10:10 2015

Thread-2: Mon Nov 21 09:10:12 2015

Ket thuc Thread-2

Đồng bộ hóa các Thread trong Python

Python cung cấp threading Module, mà bao gồm một kỹ thuật locking cho phép bạn đồng bộ hóa các Thread một cách dễ dàng. Một lock mới được tạo bởi gọi phương thức Lock().

Phương thức acquire(blocking) của đối tượng lock mới này được sử dụng để ép các Thread chạy một cách đồng bộ. Tham số blocking tùy ý cho bạn khả năng điều khiển để xem một Thread có cần đợi để đạt được lock hay không.

Nếu tham số blocking được thiết lập là 0, tức là Thread ngay lập tức trả về một giá trị 0 nếu không thu được lock và trả về giá trị 1 nếu thu được lock. Nếu blocking được thiết lập là 1, thì Thread cần đợi cho đến khi lock được giải phóng.

Phương thức release() của đối tượng lock được sử dụng để giải phóng lock khi nó không cần nữa.

Ví dụ

 import threading

import timeclass myThread (threading.Thread):

    def __init__(self, threadID, name, counter):

        threading.Thread.__init__(self)

        self.threadID = threadID

        self.name = name

        self.counter = counter

    def run(self):

        print "Bat dau " + self.name

        # Lay lock de dong bo hoa cac thread

        threadLock.acquire()

        print_time(self.name, self.counter, 3)

        # Giai phong lock cho thread ke tiep

        threadLock.release()def print_time(threadName, delay, counter):

    while counter:

        time.sleep(delay)

        print "%s: %s" % (threadName, time.ctime(time.time()))

        counter -= 1threadLock = threading.Lock()

threads = []# Tao cac thread moi

thread1 = myThread(1, "Thread-1", 1)

thread2 = myThread(2, "Thread-2", 2)# Bat dau cac thread moi

thread1.start()

thread2.start()# Them cac thread vao list

threads.append(thread1)

threads.append(thread2)# Doi cho tat ca thread ket thuc

for t in threads:

    t.join()

print "Ket thuc Main Thread"

Kết quả là:

Bat dau Thread-1

Bat dau Thread-2

Thread-1: Mon Nov 21 09:11:28 2015

Thread-1: Mon Nov 21 09:11:29 2015

Thread-1: Mon Nov 21 09:11:30 2015

Thread-2: Mon Nov 21 09:11:32 2015

Thread-2: Mon Nov 21 09:11:34 2015

Thread-2: Mon Nov 21 09:11:36 2015

Ket thuc Main Thread

Queue Module: quyền ưu tiên đa luồng trong Python

Queue Module cho phép bạn tạo một đối tượng queue mới mà có thể giữ một số lượng item nào đó. Dưới đây là các phương thức:

  • get(): Xóa và trả về một item từ queue.
  • put(): Thêm một item tới một queue.
  • qsize() : Trả về số item mà hiện tại đang trong queue.
  • empty(): Trả về true nếu queue là trống, nếu không thì trả về false.
  • full(): Trả về true nếu queue là đầy, nếu không thì trả về false.

Ví dụ

 import Queue

import threading

import timeexitFlag = 0class myThread (threading.Thread):

    def __init__(self, threadID, name, q):

        threading.Thread.__init__(self)

        self.threadID = threadID

        self.name = name

        self.q = q

    def run(self):

        print "Bat dau " + self.name

        process_data(self.name, self.q)

        print "Ket thuc " + self.namedef process_data(threadName, q):

    while not exitFlag:

        queueLock.acquire()

        if not workQueue.empty():

            data = q.get()

            queueLock.release()

            print "%s dang xu ly %s" % (threadName, data)

        else:

            queueLock.release()

        time.sleep(1)threadList = ["Thread-1", "Thread-2", "Thread-3"]

nameList = ["One", "Two", "Three", "Four", "Five"]

queueLock = threading.Lock()

workQueue = Queue.Queue(10)

threads = []

threadID = 1# Tao cac thread moi

for tName in threadList:

    thread = myThread(threadID, tName, workQueue)

    thread.start()

    threads.append(thread)

    threadID += 1# Dien vao queue

queueLock.acquire()

for word in nameList:

    workQueue.put(word)

queueLock.release()# Doi den khi queue la trong

while not workQueue.empty():

    pass# Thong bao cho thread do la thoi gian de ket thuc

exitFlag = 1# Doi cho tat ca thread ket thuc

for t in threads:

    t.join()

print "Ket thuc Main Thread"

Kết quả là:

Bat dau Thread-1

Bat dau Thread-2

Bat dau Thread-3

Thread-1 dang xu ly One

Thread-2 dang xu ly Two

Thread-3 dang xu ly Three

Thread-1 dang xu ly Four

Thread-2 dang xu ly Five

Ket thuc Thread-3

Ket thuc Thread-1

Ket thuc Thread-2

Ket thuc Main Thread