Python线程threading模块用法详解

1. 什么是Python线程?

Python线程是与操作系统线程不同的轻量级线程,它们可以在Python进程中同时运行多个线程。Python线程可以使用线程模块或Threading模块创建,如果需要更高级别的控制,则可以提供其它一些线程类。

Python线程与操作系统线程不同,它们相互独立,但是共享同一个进程空间。与线程相关的方法被定义在threading模块中,并支持常用的锁机制,如互斥锁和信号量。

2. Python线程的优点

Python线程有以下优点:

轻量级线程可以在相同的进程空间内同时运行多个线程。

共享相同的数据空间。

支持互斥锁和信号量,以避免多个线程同时读/写数据造成的死锁和竞争问题。

在扩展IO操作时比多进程更有效。

创建、启动和销毁线程的时间比多进程更有效,因为线程之间的切换开销更小。

3. Python线程的创建

Python线程可以通过两种方式创建。

3.1 使用Thread模块创建线程

使用Thread模块的方法是创建一个线程类的子类并重写run()方法。在run()方法中定义线程的行为,然后实例化该类并调用start()方法来启动线程。

import threading

class MyThread(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

print("Thread started.")

t = MyThread()

t.start()

上面的代码创建了一个名为MyThread的线程类,该类继承Thread类并重写run()方法。run()方法定义了我们需要线程完成的任务。在主程序中,我们实例化类并调用start()方法启动线程。

3.2 使用Threading模块创建线程

使用Threading模块创建线程是线程类化的另一种方法。使用Threading模块,可以简单地创建一个线程对象并传递一个函数或方法给它,并使用start()方法启动线程。

import threading

def my_function():

print("Thread started.")

t = threading.Thread(target=my_function)

t.start()

上面的代码创建了一个名为my_function的函数。我们需要将其作为参数传递给Thread对象以创建线程,然后调用start()方法启动该线程。

4. Python线程的控制

Python线程由操作系统调度,但是我们可以使用Threading模块中的方法来控制线程的行为。

4.1 join()

join()方法可以等待线程完成,然后返回。这个方法是被线程对象调用的,在主线程中调用它。主线程将等待该方法返回,这意味着它将等待线程完成。

import threading

import time

def my_function():

time.sleep(1)

print("Thread started.")

t = threading.Thread(target=my_function)

t.start()

t.join()

print("Thread finished.")

上面的代码创建了一个名为my_function的函数,将其作为参数传递给Thread对象以创建线程,调用start()方法启动线程。在主线程中,我们调用join()方法等待线程完成,然后输出"Thread finished."。

4.2 setDaemon()

setDaemon()方法可以将线程设置为后台线程。如果我们在主线程中设置一个线程对象为后台线程,那么当主线程结束时,后台线程也会结束运行。

import threading

import time

def my_function():

time.sleep(1)

print("Thread started.")

t = threading.Thread(target=my_function)

t.setDaemon(True)

t.start()

print("Main thread finished.")

上面的代码创建了一个名为my_function的函数,将其作为参数传递给Thread对象以创建线程,调用setDaemon(True)方法设置这个线程为后台线程。在主程序中,我们打印 "Main thread finished."后即可退出,但后台线程仍会继续运行。

4.3 enumerate()

enumerate()方法可以返回所有线程正运行的列表。

import threading

def my_function():

print("Thread started.")

t1 = threading.Thread(target=my_function)

t2 = threading.Thread(target=my_function)

t1.start()

t2.start()

print(threading.enumerate())

上面的代码创建了两个线程并启动它们。我们使用enumerate()方法列出所有正在运行的线程对象列表。

5. Python线程的同步

线程同步方法可以避免多个线程同时读/写数据所导致的竞争和死锁问题。

5.1 Lock锁

互斥锁(Lock)是一种简单的同步方法,只有拥有锁的线程才能访问共享资源。如果另一个线程尝试访问该锁,它将会在这里阻塞,直到第一个线程释放锁。一个简单的例子是两个线程交替输出数字:

import threading

class MyThread(threading.Thread):

def __init__(self, thread_id, lock):

threading.Thread.__init__(self)

self.thread_id = thread_id

self.lock = lock

def run(self):

for i in range(10):

self.lock.acquire()

print("Thread", self.thread_id, "prints", i)

self.lock.release()

lock = threading.Lock()

t1 = MyThread(1, lock)

t2 = MyThread(2, lock)

t1.start()

t2.start()

上面的代码创建了一个名为MyThread的线程类,该类继承Thread类并重写run()方法。在run()方法中,每个线程在输出数字前获取锁,输出后释放锁。在主程序中,我们实例化类并创建两个线程对象,两个线程对象共享同一个锁对象,最终实现了两个线程交替地输出数字。

5.2 Semaphore信号量

Semaphore是一种同步方法,它可以限制同时访问某些共享资源的线程数量。如果设定的数量大于1,则Semaphore允许多个线程同时访问该资源。

import threading

class MyThread(threading.Thread):

def __init__(self, thread_id, sem):

threading.Thread.__init__(self)

self.thread_id = thread_id

self.sem = sem

def run(self):

self.sem.acquire()

print("Thread", self.thread_id, "starts.")

self.sem.release()

sem = threading.Semaphore(4)

threads = []

for i in range(10):

threads.append(MyThread(i, sem))

for t in threads:

t.start()

上面的代码创建了一个名为MyThread的线程类,该类继承Thread类并重写run()方法。在run()方法中,每个线程在访问资源前获取锁,输出后释放锁。在主程序中,我们创建了一个名为sem的Semaphore对象,定义了多个线程,并在每个线程中使用semaphore来限制线程数量。在这种情况下,Semaphore对象将允许最多4个线程同时运行。在所有线程完成后,该程序将退出。

6. 总结

Python线程是轻量级线程,在Python进程中同时运行多个线程。Python线程可以使用线程模块或Threading模块创建,如果需要更高级别的控制,则可以提供其它一些线程类。Python线程支持互斥锁和信号量,以避免多个线程同时读/写数据造成的死锁和竞争问题。

后端开发标签