python 线程中常用的两个模块为: _threadthreading (推荐使用)。(注: thread 模块已经被废弃,用户可以使用 threading 模块代替,所以 python3 中不能再使用 thread 模块,为了兼容性, python3thread 重命名为 _thread

# 一、Python 的线程使用方式

   Python 中使用线程有两种方式:函数或者用类来包装线程对象。(分别对应 _threadthreading 模块)

# 1.1 _thread - 函数式线程

  调用 _thread 模块中的 start_new_thread() 函数来产生新线程。语法如下:

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

参数说明:

  • function - 线程函数。
  • args - 传递给线程函数的参数,他必须是个 tuple 类型。
  • kwargs - 可选参数。
      使用案例如下:
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: 无法启动线程")
while 1:
    pass

  执行以上程序输出结果如下:

Thread-1: Tue Apr 11 14:50:13 2023
Thread-2: Tue Apr 11 14:50:15 2023
Thread-1: Tue Apr 11 14:50:15 2023
Thread-1: Tue Apr 11 14:50:17 2023
Thread-2: Tue Apr 11 14:50:19 2023
Thread-1: Tue Apr 11 14:50:19 2023
Thread-1: Tue Apr 11 14:50:21 2023
Thread-2: Tue Apr 11 14:50:23 2023
Thread-2: Tue Apr 11 14:50:27 2023
Thread-2: Tue Apr 11 14:50:31 2023

# 1.2 threading - 类包装式线程

   _thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。 threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:

  • threading.currentThread() : 返回当前的线程变量。
  • threading.enumerate() : 返回一个包含正在运行的线程的 list 。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.activeCount() : 返回正在运行的线程数量,与 len(threading.enumerate()) 有相同的结果。
      除了使用方法外,线程模块同样提供了 Thread 类来处理线程,Thread 类提供了以下方法:
  • run() : 用以表示线程活动的方法。
  • start() : 启动线程活动。
  • join([time]) : 等待至线程中止。这阻塞调用线程直至线程的 join() 方法被调用中止 - 正常退出或者抛出未处理的异常 - 或者是可选的超时发生。
  • isAlive() : 返回线程是否活动的。
  • getName() : 返回线程名。
  • setName() : 设置线程名。
      我们可以通过直接从 threading.Thread 继承创建一个新的子类,并实例化后调用 start() 方法启动新线程,即它调用了线程的 run() 方法。使用案例如下:
import threading
import time
class myThread(threading.Thread):
    def __init__(self, threadID, name, delay):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.delay = delay
    def run(self):
        print("开始线程:" + self.name)
        print_time(self.name, self.delay, 5)
        print("退出线程:" + self.name)
def print_time(threadName, delay, counter):
    while counter:
        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("退出主线程")

  以上程序执行结果如下:

开始线程:Thread-1
开始线程:Thread-2
Thread-1: Tue Apr 11 14:52:32 2023
Thread-2: Tue Apr 11 14:52:33 2023
Thread-1: Tue Apr 11 14:52:33 2023
Thread-1: Tue Apr 11 14:52:34 2023
Thread-2: Tue Apr 11 14:52:35 2023
Thread-1: Tue Apr 11 14:52:35 2023
Thread-1: Tue Apr 11 14:52:36 2023
退出线程:Thread-1
Thread-2: Tue Apr 11 14:52:37 2023
Thread-2: Tue Apr 11 14:52:39 2023
Thread-2: Tue Apr 11 14:52:41 2023
退出线程:Thread-2
退出主线程

# 三、线程中止

  如果想要使线程在运行规定一段时间之后结束,可以通过在线程的类中添加运行状态的变量,并在其他线程中记录时间,当其他线程记录时间到达时改变子线程的运行状态变量,子线程根据判断跳出 run () 程序来结束该程序。
  ⚠️⚠️⚠️由于本人并没有在网上找到其他更加方便的中止线程的方法,故自己设计了这种效率较低的中止方法

import threading
import time
class myThread(threading.Thread):
    def __init__(self, threadID, name, delay):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.delay = delay
        self.run_state = True
    def run(self):
        print("开始线程:" + self.name)
        self.print_time(5)
        print("退出线程:" + self.name)
    def exit(self):
        self.run_state = False
    def print_time(self, counter):
        while counter:
            if self.run_state:
                time.sleep(self.delay)
                print("%s: %s" % (self.name, time.ctime(time.time())))
                counter -= 1
            else:
                print("线程被中止:" + self.name)
                break
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
# 开启新线程
thread1.start()
# 中止子线程
time.sleep(3)
thread1.exit()

  以上程序执行结果如下:

开始线程:Thread-1
Thread-1: Tue Apr 11 15:33:35 2023
Thread-1: Tue Apr 11 15:33:36 2023
Thread-1: Tue Apr 11 15:33:37 2023
线程被中止:Thread-1
退出线程:Thread-1

# 四、Thread.join 用法详解

   join() 方法的主要作用是阻塞主线程,其格式为 thread.join(timeout)timeout 参数作为可选参数,其功能是指定 thread 线程最多阻塞主线程的时间(以秒为单位),如果省略,则默认直到 thread 执行结束(进入死亡状态)才释放主线程。简单理解为 join() 了多长时间,那么主线程就会被阻塞多长时间。如下展示了 join() 的三种情况:

# 4.1 没有使用 join

  此时主线程和子线程相当于齐头并进,主线程不会等待子线程执行完了再结束,即不会阻塞。

import threading
import time
class myThread(threading.Thread):
    def __init__(self, threadID, name, delay):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.delay = delay
    def run(self):
        print("开始线程:" + self.name)
        print_time(self.name, self.delay, 10)
        print("退出线程:" + self.name)
def print_time(threadName, delay, counter):
    while counter:
        time.sleep(delay)
        print("%s: %s" % (threadName, time.ctime(time.time())))
        counter -= 1
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
# 开启新线程
thread1.start()
print("退出主线程")

  以上程序执行结果如下:

开始线程:Thread-1退出主线程
Thread-1: Tue Apr 11 15:35:25 2023
Thread-1: Tue Apr 11 15:35:26 2023
Thread-1: Tue Apr 11 15:35:27 2023
Thread-1: Tue Apr 11 15:35:28 2023
Thread-1: Tue Apr 11 15:35:29 2023
Thread-1: Tue Apr 11 15:35:30 2023
Thread-1: Tue Apr 11 15:35:31 2023
Thread-1: Tue Apr 11 15:35:32 2023
Thread-1: Tue Apr 11 15:35:33 2023
Thread-1: Tue Apr 11 15:35:34 2023
退出线程:Thread-1

# 4.2 使用 join 但没有设置参数(最常用)

当主线程内的子线程都 start 后,主线程会阻塞并等待子线程执行完才继续执行,直观的表现是:子线程都 start 后,主线程若还有未执行的代码,此时不会继续执行剩余代码,而是等待子线程都执行完后再执行。

import threading
import time
class myThread(threading.Thread):
    def __init__(self, threadID, name, delay):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.delay = delay
    def run(self):
        print("开始线程:" + self.name)
        print_time(self.name, self.delay, 10)
        print("退出线程:" + self.name)
def print_time(threadName, delay, counter):
    while counter:
        time.sleep(delay)
        print("%s: %s" % (threadName, time.ctime(time.time())))
        counter -= 1
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
# 开启新线程
thread1.start()
thread1.join()
print("退出主线程")

  以上程序执行结果如下:

开始线程:Thread-1
Thread-1: Tue Apr 11 15:37:20 2023
Thread-1: Tue Apr 11 15:37:21 2023
Thread-1: Tue Apr 11 15:37:22 2023
Thread-1: Tue Apr 11 15:37:23 2023
Thread-1: Tue Apr 11 15:37:24 2023
Thread-1: Tue Apr 11 15:37:25 2023
Thread-1: Tue Apr 11 15:37:26 2023
Thread-1: Tue Apr 11 15:37:27 2023
Thread-1: Tue Apr 11 15:37:28 2023
Thread-1: Tue Apr 11 15:37:29 2023
退出线程:Thread-1
退出主线程

# 4.3 有 join 并设置参数

  设置了主线程最长阻塞时间,但即使是主线程结束阻塞后执行完剩余代码,子线程也会继续执行,而不会随着主线程的结束而终止。

import threading
import time
class myThread(threading.Thread):
    def __init__(self, threadID, name, delay):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.delay = delay
    def run(self):
        print("开始线程:" + self.name)
        print_time(self.name, self.delay, 10)
        print("退出线程:" + self.name)
def print_time(threadName, delay, counter):
    while counter:
        time.sleep(delay)
        print("%s: %s" % (threadName, time.ctime(time.time())))
        counter -= 1
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
# 开启新线程
thread1.start()
thread1.join(3)
print("退出主线程")

  以上程序执行结果如下:

开始线程:Thread-1
Thread-1: Tue Apr 11 15:37:56 2023
Thread-1: Tue Apr 11 15:37:57 2023
退出主线程
Thread-1: Tue Apr 11 15:37:58 2023
Thread-1: Tue Apr 11 15:37:59 2023
Thread-1: Tue Apr 11 15:38:00 2023
Thread-1: Tue Apr 11 15:38:01 2023
Thread-1: Tue Apr 11 15:38:02 2023
Thread-1: Tue Apr 11 15:38:03 2023
Thread-1: Tue Apr 11 15:38:04 2023
Thread-1: Tue Apr 11 15:38:05 2023
退出线程:Thread-1
更新于 阅读次数