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