Thực hiện chủ đề

Trong chương này, chúng ta sẽ học cách triển khai các luồng trong Python.

Mô-đun Python để triển khai chuỗi

Các luồng Python đôi khi được gọi là các quy trình nhẹ vì các luồng chiếm ít bộ nhớ hơn nhiều so với các quy trình. Chủ đề cho phép thực hiện nhiều tác vụ cùng một lúc. Trong Python, chúng ta có hai mô-đun sau đây triển khai các luồng trong một chương trình:

  • <_thread>module

  • <threading>module

Sự khác biệt chính giữa hai mô-đun này là <_thread> mô-đun coi một luồng như một hàm trong khi, <threading>mô-đun coi mọi luồng như một đối tượng và thực hiện nó theo cách hướng đối tượng. Hơn nữa,<_thread>mô-đun hiệu quả trong phân luồng cấp thấp và có ít khả năng hơn <threading> mô-đun.

mô-đun <_thread>

Trong phiên bản Python trước đó, chúng tôi đã có <thread>nhưng nó đã được coi là "không được chấp nhận" trong một thời gian khá dài. Người dùng đã được khuyến khích sử dụng<threading>mô-đun thay thế. Do đó, trong Python 3, "luồng" mô-đun không có sẵn nữa. Nó đã được đổi tên thành "<_thread>"cho sự không tương thích ngược trong Python3.

Để tạo chuỗi mới với sự trợ giúp của <_thread> mô-đun, chúng ta cần gọi start_new_threadphương pháp của nó. Hoạt động của phương pháp này có thể được hiểu với sự trợ giúp của cú pháp sau:

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

Đây -

  • args là một loạt các đối số

  • kwargs là một từ điển tùy chọn của các đối số từ khóa

Nếu chúng ta muốn gọi hàm mà không truyền đối số thì chúng ta cần sử dụng một bộ đối số trống trong args.

Lệnh gọi phương thức này trả về ngay lập tức, luồng con bắt đầu và gọi hàm với danh sách args đã truyền, nếu có. Luồng kết thúc khi và khi hàm trả về.

Thí dụ

Sau đây là một ví dụ để tạo chuỗi mới bằng cách sử dụng <_thread>mô-đun. Chúng tôi đang sử dụng phương thức start_new_thread () ở đây.

import _thread
import time

def print_time( threadName, delay):
   count = 0
   while count < 5:
      time.sleep(delay)
      count += 1
      print ("%s: %s" % ( threadName, time.ctime(time.time()) ))

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

Đầu ra

Kết quả đầu ra sau đây sẽ giúp chúng ta hiểu thế hệ của các luồng mới với sự trợ giúp của <_thread> mô-đun.

Thread-1: Mon Apr 23 10:03:33 2018
Thread-2: Mon Apr 23 10:03:35 2018
Thread-1: Mon Apr 23 10:03:35 2018
Thread-1: Mon Apr 23 10:03:37 2018
Thread-2: Mon Apr 23 10:03:39 2018
Thread-1: Mon Apr 23 10:03:39 2018
Thread-1: Mon Apr 23 10:03:41 2018
Thread-2: Mon Apr 23 10:03:43 2018
Thread-2: Mon Apr 23 10:03:47 2018
Thread-2: Mon Apr 23 10:03:51 2018

mô-đun <threading>

Các <threading>mô-đun thực thi theo cách hướng đối tượng và coi mọi luồng như một đối tượng. Do đó, nó cung cấp hỗ trợ cấp cao, mạnh mẽ hơn cho các luồng so với mô-đun <_thread>. Mô-đun này được bao gồm với Python 2.4.

Các phương thức bổ sung trong mô-đun <threading>

Các <threading> mô-đun bao gồm tất cả các phương thức của <_thread>nhưng nó cũng cung cấp các phương pháp bổ sung. Các phương pháp bổ sung như sau:

  • threading.activeCount() - Phương thức này trả về số lượng đối tượng luồng đang hoạt động

  • threading.currentThread() - Phương thức này trả về số đối tượng luồng trong điều khiển luồng của người gọi.

  • threading.enumerate() - Phương thức này trả về danh sách tất cả các đối tượng luồng hiện đang hoạt động.

  • Để triển khai luồng, <threading> mô-đun có Thread lớp cung cấp các phương thức sau:

    • run() - Phương thức run () là điểm vào của một luồng.

    • start() - Phương thức start () bắt đầu một luồng bằng cách gọi phương thức run.

    • join([time]) - Tham gia () đợi các luồng kết thúc.

    • isAlive() - Phương thức isAlive () kiểm tra xem một luồng có còn đang thực thi hay không.

    • getName() - Phương thức getName () trả về tên của một luồng.

    • setName() - Phương thức setName () đặt tên của một luồng.

Làm cách nào để tạo luồng bằng mô-đun <threading>?

Trong phần này, chúng ta sẽ học cách tạo chuỗi bằng cách sử dụng <threading>mô-đun. Làm theo các bước sau để tạo một chuỗi mới bằng mô-đun <threading> -

  • Step 1 - Trong bước này, chúng ta cần xác định một lớp con mới của Thread lớp học.

  • Step 2 - Sau đó, để thêm các đối số bổ sung, chúng ta cần ghi đè __init__(self [,args]) phương pháp.

  • Step 3 - Ở bước này, chúng ta cần ghi đè phương thức run (self [, args]) để thực thi những gì mà luồng sẽ làm khi bắt đầu.

  • Bây giờ, sau khi tạo Thread lớp con, chúng ta 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 start(), lần lượt gọi run() phương pháp.

Thí dụ

Hãy xem xét ví dụ này để tìm hiểu cách tạo một chuỗi mới bằng cách sử dụng <threading> mô-đun.

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, self.counter, 5)
      print ("Exiting " + self.name)
def print_time(threadName, delay, counter):
   while counter:
      if exitFlag:
         threadName.exit()
      time.sleep(delay)
      print ("%s: %s" % (threadName, time.ctime(time.time())))
      counter -= 1

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

thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("Exiting Main Thread")
Starting Thread-1
Starting Thread-2

Đầu ra

Bây giờ, hãy xem xét kết quả sau:

Thread-1: Mon Apr 23 10:52:09 2018
Thread-1: Mon Apr 23 10:52:10 2018
Thread-2: Mon Apr 23 10:52:10 2018
Thread-1: Mon Apr 23 10:52:11 2018
Thread-1: Mon Apr 23 10:52:12 2018
Thread-2: Mon Apr 23 10:52:12 2018
Thread-1: Mon Apr 23 10:52:13 2018
Exiting Thread-1
Thread-2: Mon Apr 23 10:52:14 2018
Thread-2: Mon Apr 23 10:52:16 2018
Thread-2: Mon Apr 23 10:52:18 2018
Exiting Thread-2
Exiting Main Thread

Chương trình Python cho các trạng thái luồng khác nhau

Có năm trạng thái luồng - mới, chạy được, đang chạy, đang chờ và đã chết. Trong số năm Trong số năm trạng thái này, chúng tôi sẽ chủ yếu tập trung vào ba trạng thái - chạy, chờ và chết. Một luồng nhận tài nguyên của nó ở trạng thái đang chạy, đợi tài nguyên ở trạng thái chờ; bản phát hành cuối cùng của tài nguyên, nếu việc thực thi và thu được ở trạng thái chết.

Chương trình Python sau đây với sự trợ giúp của các phương thức start (), sleep () và join () sẽ hiển thị cách một luồng được nhập vào trạng thái chạy, chờ và chết tương ứng.

Step 1 - Nhập các mô-đun cần thiết, <threading> và <time>

import threading
import time

Step 2 - Định nghĩa một hàm sẽ được gọi trong khi tạo một luồng.

def thread_states():
   print("Thread entered in running state")

Step 3 - Chúng tôi đang sử dụng phương thức sleep () của mô-đun thời gian để làm cho chuỗi của chúng tôi chờ trong 2 giây.

time.sleep(2)

Step 4 - Bây giờ, chúng ta đang tạo một luồng có tên là T1, luồng này lấy đối số của hàm đã định nghĩa ở trên.

T1 = threading.Thread(target=thread_states)

Step 5- Bây giờ, với sự trợ giúp của hàm start (), chúng ta có thể bắt đầu luồng của mình. Nó sẽ tạo ra thông báo, được thiết lập bởi chúng tôi trong khi xác định chức năng.

T1.start()
Thread entered in running state

Step 6 - Bây giờ, cuối cùng chúng ta có thể giết luồng bằng phương thức join () sau khi nó kết thúc quá trình thực thi.

T1.join()

Bắt đầu một chuỗi bằng Python

Trong python, chúng ta có thể bắt đầu một luồng mới bằng nhiều cách khác nhau nhưng cách dễ nhất trong số đó là xác định nó như một hàm duy nhất. Sau khi xác định hàm, chúng ta có thể chuyển nó làm mục tiêu cho mộtthreading.Threadđối tượng và như vậy. Thực thi mã Python sau để hiểu cách hoạt động của hàm:

import threading
import time
import random
def Thread_execution(i):
   print("Execution of Thread {} started\n".format(i))
   sleepTime = random.randint(1,4)
   time.sleep(sleepTime)
   print("Execution of Thread {} finished".format(i))
for i in range(4):
   thread = threading.Thread(target=Thread_execution, args=(i,))
   thread.start()
   print("Active Threads:" , threading.enumerate())

Đầu ra

Execution of Thread 0 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>]

Execution of Thread 1 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>]

Execution of Thread 2 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>,
      <Thread(Thread-3578, started 2268)>]

Execution of Thread 3 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>,
      <Thread(Thread-3578, started 2268)>,
      <Thread(Thread-3579, started 4520)>]
Execution of Thread 0 finished
Execution of Thread 1 finished
Execution of Thread 2 finished
Execution of Thread 3 finished

Chuỗi Daemon trong Python

Trước khi triển khai các luồng daemon trong Python, chúng ta cần biết về các luồng daemon và cách sử dụng chúng. Về mặt máy tính, daemon là một tiến trình nền xử lý các yêu cầu cho các dịch vụ khác nhau như gửi dữ liệu, truyền tệp, v.v. Nó sẽ không hoạt động nếu nó không được yêu cầu nữa. Tác vụ tương tự cũng có thể được thực hiện với sự trợ giúp của các luồng không phải daemon. Tuy nhiên, trong trường hợp này, luồng chính phải theo dõi các luồng không phải daemon theo cách thủ công. Mặt khác, nếu chúng ta đang sử dụng các luồng daemon thì luồng chính hoàn toàn có thể quên điều này và nó sẽ bị giết khi luồng chính thoát ra. Một điểm quan trọng khác về các luồng daemon là chúng ta có thể chọn chỉ sử dụng chúng cho các tác vụ không thiết yếu sẽ không ảnh hưởng đến chúng ta nếu nó không hoàn thành hoặc bị giết ở giữa. Sau đây là cách triển khai các luồng daemon trong python:

import threading
import time

def nondaemonThread():
   print("starting my thread")
   time.sleep(8)
   print("ending my thread")
def daemonThread():
   while True:
   print("Hello")
   time.sleep(2)
if __name__ == '__main__':
   nondaemonThread = threading.Thread(target = nondaemonThread)
   daemonThread = threading.Thread(target = daemonThread)
   daemonThread.setDaemon(True)
   daemonThread.start()
   nondaemonThread.start()

Trong đoạn mã trên, có hai chức năng cụ thể là >nondaemonThread()>daemonThread(). Hàm đầu tiên in trạng thái của nó và ngủ sau 8 giây trong khi hàm deamonThread () in Hello sau mỗi 2 giây vô thời hạn. Chúng ta có thể hiểu sự khác biệt giữa các luồng nondaemon và daemon với sự trợ giúp của đầu ra sau:

Hello

starting my thread
Hello
Hello
Hello
Hello
ending my thread
Hello
Hello
Hello
Hello
Hello