Cộng đồng chia sẻ tri thức Lib24.vn

Python - Lập trình đa luồng

Gửi bởi: Phạm Thọ Thái Dương 20 tháng 2 2020 lúc 11:00:27


Mục lục
* * * * *

Chạy một số luồng tương tự như chạy đồng thời một số chương trình khác nhau, nhưng với các lợi ích sau -

  1. Nhiều luồng trong một tiến trình chia sẻ cùng một không gian dữ liệu với luồng chính và do đó có thể chia sẻ thông tin hoặc liên lạc với nhau dễ dàng hơn nếu chúng là các tiến trình riêng biệt.
  2. Chủ đề đôi khi được gọi là quá trình trọng lượng nhẹ và chúng không đòi hỏi nhiều bộ nhớ; chúng rẻ hơn các quy trình.

Một chủ đề có một khởi đầu, một chuỗi thực hiện và kết luận. Nó có một con trỏ lệnh theo dõi vị trí trong bối cảnh hiện tại nó đang chạy.

  1. Nó có thể được làm trống trước (bị gián đoạn)
  2. Nó có thể tạm thời bị giữ (còn được gọi là ngủ) trong khi các luồng khác đang chạy - điều này được gọi là năng suất.

Bắt đầu một chủ đề mới

Để sinh ra một luồng khác, bạn cần gọi phương thức sau có sẵn trong mô-đun luồng -

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

Cuộc gọi phương thức này cho phép một cách nhanh chóng và hiệu quả để tạo các luồng mới trong cả Linux và Windows.

Trở về phương pháp gọi ngay và đứa trẻ bắt đầu chủ đề và các cuộc gọi hoạt động với danh sách thông qua các args . Khi hàm trả về, luồng kết thúc.

Ở đây, args là một bộ các lập luận; sử dụng một tuple trống để gọi hàm mà không truyền bất kỳ đối số nào. kwargs là một từ điển tùy chọn của các đối số từ khóa.

Thí dụ

#!/usr/bin/python

import thread
import time

# Define a function for the thread
def print_time( threadName, delay):
   count = 0
   while count < 5:
      time.sleep(delay)
      count += 1
      print "%s: %s" % ( threadName, time.ctime(time.time()) )

# Create two threads as follows
try:
   thread.start_new_thread( print_time, ("Thread-1", 2, ) )
   thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
   print "Error: unable to start thread"

while 1:
   pass

Khi đoạn mã trên được thực thi, nó tạo ra kết quả sau -

Thread-1: Thu Jan 22 15:42:17 2009
Thread-1: Thu Jan 22 15:42:19 2009
Thread-2: Thu Jan 22 15:42:19 2009
Thread-1: Thu Jan 22 15:42:21 2009
Thread-2: Thu Jan 22 15:42:23 2009
Thread-1: Thu Jan 22 15:42:23 2009
Thread-1: Thu Jan 22 15:42:25 2009
Thread-2: Thu Jan 22 15:42:27 2009
Thread-2: Thu Jan 22 15:42:31 2009
Thread-2: Thu Jan 22 15:42:35 2009

Mặc dù nó rất hiệu quả đối với phân luồng cấp thấp, nhưng mô-đun luồng rất hạn chế so với mô-đun luồng mới hơn.

Các Threading Mô-đun

Mô-đun luồng mới hơn đi kèm với Python 2.4 cung cấp hỗ trợ cấp cao, mạnh mẽ hơn nhiều cho các luồng so với mô-đun luồng đã thảo luận trong phần trước.

Các luồng mô-đun cho thấy tất cả các phương pháp của chủ đề mô-đun và cung cấp một số phương pháp bổ sung -

  1. threading.activeCount () - Trả về số lượng đối tượng luồng đang hoạt động.
  2. threading.cienThread () - Trả về số lượng đối tượng luồng trong điều khiển luồng của trình gọi.
  3. threading.enum Cả () - Trả về danh sách tất cả các đối tượng luồng hiện đang hoạt động.

Ngoài các phương thức, mô đun luồng có lớp Thread thực hiện luồng. Các phương thức được cung cấp bởi lớp Thread như sau -

  1. run () - Phương thức run () là điểm vào cho một luồng.
  2. start () - Phương thức start () bắt đầu một luồng bằng cách gọi phương thức run.
  3. tham gia ([thời gian]) - Tham gia () chờ đợi các chủ đề kết thúc.
  4. isAlive () - Phương thức isAlive () kiểm tra xem một luồng có còn thực thi hay không.
  5. getName () - Phương thức getName () trả về tên của một luồng.
  6. setName () - Phương thức setName () đặt tên của một luồng.

Tạo chủ đề bằng mô-đun luồng

Để thực hiện một luồng mới bằng cách sử dụng mô đun luồng, bạn phải làm như sau -

  1. Xác định một lớp con mới của lớp Thread .
  2. Ghi đè phương thức __init __ (self [, args]) để thêm đối số bổ sung.
  3. Sau đó, ghi đè phương thức run (self [, args]) để thực hiện những gì luồng nên làm khi bắt đầu.

Khi bạn đã tạo lớp con Thread mới , bạn có thể tạo một thể hiện của nó và sau đó bắt đầu một luồng mới bằng cách gọi phương thức start () , lần lượt gọi phương thức run () .

Thí dụ

#!/usr/bin/python

import threading
import time

exitFlag = 0

class 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 "Starting " + self.name
      print_time(self.name, 5, self.counter)
      print "Exiting " + self.name

def print_time(threadName, counter, delay):
   while counter:
      if exitFlag:
         threadName.exit()
      time.sleep(delay)
      print "%s: %s" % (threadName, time.ctime(time.time()))
      counter -= 1

# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# Start new Threads
thread1.start()
thread2.start()

print "Exiting Main Thread"

Khi đoạn mã trên được thực thi, nó tạo ra kết quả sau -

Starting Thread-1
Starting Thread-2
Exiting Main Thread
Thread-1: Thu Mar 21 09:10:03 2013
Thread-1: Thu Mar 21 09:10:04 2013
Thread-2: Thu Mar 21 09:10:04 2013
Thread-1: Thu Mar 21 09:10:05 2013
Thread-1: Thu Mar 21 09:10:06 2013
Thread-2: Thu Mar 21 09:10:06 2013
Thread-1: Thu Mar 21 09:10:07 2013
Exiting Thread-1
Thread-2: Thu Mar 21 09:10:08 2013
Thread-2: Thu Mar 21 09:10:10 2013
Thread-2: Thu Mar 21 09:10:12 2013
Exiting Thread-2

Đồng bộ hóa chủ đề

Mô-đun luồng được cung cấp với Python bao gồm cơ chế khóa đơn giản để thực hiện cho phép bạn đồng bộ hóa các luồng. Một khóa mới được tạo bằng cách gọi phương thức Lock () , trả về khóa mới.

Phương thức thu (chặn) của đối tượng khóa mới được sử dụng để buộc các luồng chạy đồng bộ. Tham số chặn tùy chọn cho phép bạn kiểm soát xem luồng có chờ lấy khóa hay không.

Nếu chặn được đặt thành 0, luồng sẽ trả về ngay lập tức với giá trị 0 nếu không thể lấy được khóa và với 1 nếu khóa được lấy. Nếu chặn được đặt thành 1, khối luồng và chờ khóa được giải phóng.

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

Thí dụ

#!/usr/bin/python

import threading
import time

class 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 "Starting " + self.name
      # Get lock to synchronize threads
      threadLock.acquire()
      print_time(self.name, self.counter, 3)
      # Free lock to release next thread
      threadLock.release()

def print_time(threadName, delay, counter):
   while counter:
      time.sleep(delay)
      print "%s: %s" % (threadName, time.ctime(time.time()))
      counter -= 1

threadLock = threading.Lock()
threads = []

# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# Start new Threads
thread1.start()
thread2.start()

# Add threads to thread list
threads.append(thread1)
threads.append(thread2)

# Wait for all threads to complete
for t in threads:
    t.join()
print "Exiting Main Thread"

Khi đoạn mã trên được thực thi, nó tạo ra kết quả sau -

Starting Thread-1
Starting Thread-2
Thread-1: Thu Mar 21 09:11:28 2013
Thread-1: Thu Mar 21 09:11:29 2013
Thread-1: Thu Mar 21 09:11:30 2013
Thread-2: Thu Mar 21 09:11:32 2013
Thread-2: Thu Mar 21 09:11:34 2013
Thread-2: Thu Mar 21 09:11:36 2013
Exiting Main Thread

Hàng đợi ưu tiên đa luồng

Các Queue mô-đun cho phép bạn tạo một đối tượng hàng đợi mới có thể tổ chức một số cụ thể của các mặt hàng. Có các phương pháp sau để kiểm soát Hàng đợi -

  1. get () - get () loại bỏ và trả về một mục từ hàng đợi.
  2. put () - Việc đặt thêm mục vào hàng đợi.
  3. qsize () - qsize () trả về số lượng các mục hiện có trong hàng đợi.
  4. blank () - rỗng () trả về True nếu hàng đợi trống; mặt khác, sai
  5. full () - full () trả về True nếu hàng đợi đầy; mặt khác, sai

Thí dụ

#!/usr/bin/python

import Queue
import threading
import time

exitFlag = 0

class 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 "Starting " + self.name
      process_data(self.name, self.q)
      print "Exiting " + self.name

def process_data(threadName, q):
   while not exitFlag:
      queueLock.acquire()
         if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print "%s processing %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

# Create new threads
for tName in threadList:
   thread = myThread(threadID, tName, workQueue)
   thread.start()
   threads.append(thread)
   threadID += 1

# Fill the queue
queueLock.acquire()
for word in nameList:
   workQueue.put(word)
queueLock.release()

# Wait for queue to empty
while not workQueue.empty():
   pass

# Notify threads it's time to exit
exitFlag = 1

# Wait for all threads to complete
for t in threads:
   t.join()
print "Exiting Main Thread"

Khi đoạn mã trên được thực thi, nó tạo ra kết quả sau -

Starting Thread-1
Starting Thread-2
Starting Thread-3
Thread-1 processing One
Thread-2 processing Two
Thread-3 processing Three
Thread-1 processing Four
Thread-2 processing Five
Exiting Thread-3
Exiting Thread-1
Exiting Thread-2
Exiting Main Thread

Được cập nhật: 26 tháng 3 lúc 22:21:31 | Lượt xem: 1478