您的位置:

Python多线程编程:活跃线程的管理和控制

一、线程管理

在多线程编程中,线程管理是一个非常重要的部分。在Python中,线程可以通过Thread类进行创建和控制。


import threading
import time

def worker():
    print("Worker start.")
    time.sleep(5)
    print("Worker end.")

t1 = threading.Thread(target=worker)
t1.start()

上面的代码通过Thread类创建了一个名叫t1的线程,并传入了worker函数作为线程的执行函数。执行t1.start()后,该线程就开始执行了。在这个例子中,worker函数是一个简单的模拟耗时操作的函数,执行5秒后就结束。当线程执行完成后,Python解释器并不会自动将其销毁,需要调用t1.join()方法等待线程执行完毕,或者调用t1.is_alive()方法判断线程是否还在执行。

二、线程控制

线程控制是多线程编程中的关键部分,可以通过一些方法对线程进行控制,比如等待线程执行完成、终止线程等。

1.等待线程执行完成

在多线程编程中,常见的需求就是等待所有子线程执行完成之后再进行后续操作,可以通过遍历所有线程来实现。


import threading
import time

def worker():
    print("Worker start.")
    time.sleep(5)
    print("Worker end.")

threads = []
for i in range(5):
    t = threading.Thread(target=worker)
    t.start()
    threads.append(t)

for t in threads:
    t.join()

print("All workers done.")

上面的代码中,创建了5个线程并挂起,每个线程执行5秒后结束。在创建完所有线程之后,遍历所有线程并执行t.join()等待线程执行完毕。执行完毕后会打印出"All workers done."。

2.终止线程

终止线程是一种非常危险的操作,只有在必要时才应该使用。可以通过设置线程的stop标志位或者调用线程的terminate()方法来终止线程。

(1)设置stop标志位

可以通过设置线程的stop标志位,来令线程主动结束。


import threading
import time

class MyThread(threading.Thread):
    def __init__(self):
        super(MyThread, self).__init__()
        self.stop = False
        
    def run(self):
        print("Thread start.")
        while not self.stop:
            print("Thread is running.")
            time.sleep(1)
        print("Thread end.")
        
    def stop_thread(self):
        self.stop = True

t = MyThread()
t.start()

time.sleep(5)

t.stop_thread()

上面的代码中,自定义了一个MyThread类,线程执行的代码在run方法中。run方法通过检查stop标志位来判断线程是否应该结束,并在需要时结束线程。当需要结束线程时,调用MyThread的stop_thread方法,将stop标志位设置为True即可。

(2)调用terminate()方法

还可以直接调用线程的terminate()方法来终止线程,但是该方法很危险,应该在必要时才使用。因为线程在执行过程中可能会持有锁或者其他资源,在线程被突然终止的情况下,可能会导致这些资源被永久占用。


import threading
import time

def worker():
    print("Worker start.")
    while True:
        print("Worker is running.")
        time.sleep(1)

t = threading.Thread(target=worker)
t.start()

time.sleep(5)

t.terminate() # 终止线程

三、线程同步

在多线程编程中,线程之间可能会存在一些共享资源,如果多个线程同时对这些资源进行读写,就可能导致数据不一致或者异常情况。为了解决这个问题,需要使用线程同步机制来协调多个线程的操作。

1.Lock对象

Lock对象可以用来协调多个线程对临界区的访问。临界区就是指多个线程都要访问的共享资源区域,需要在访问该区域之前获取锁,访问完毕后释放锁。


import threading
import time

class SharedResource:
    def __init__(self):
        self.lock = threading.Lock()
        self.count = 0
        
    def increment(self):
        with self.lock:
            self.count += 1
            print("SharedResource: ", self.count)

def worker(resource):
    for i in range(5):
        resource.increment()
        time.sleep(1)

resource = SharedResource()
threads = []
for i in range(3):
    t = threading.Thread(target=worker, args=(resource,))
    t.start()
    threads.append(t)

for t in threads:
    t.join()

print("All workers done.")

上面的代码中,自定义了一个SharedResource类,该类维护了一个共享计数器count。increment方法对计数器进行加1操作,并使用with锁语句获取锁,避免多个线程同时修改计数器。在worker函数中创建了3个线程,并让每个线程调用5次increment方法,每次调用前都会获取锁进行保护。执行完毕后打印"All workers done."。

2.Condition对象

Condition对象也可以用来协调多个线程的访问。与Lock对象不同的是,Condition对象可以在特定变量满足某些条件时,释放所有等待该条件的线程,也可以在某个条件被满足时唤醒所有等待的线程。


import threading
import time

class SharedResource:
    def __init__(self):
        self.lock = threading.Lock()
        self.condition = threading.Condition(self.lock)
        self.count = 0
        
    def increment(self):
        with self.lock:
            self.count += 1
            print("SharedResource: ", self.count)
            if self.count >= 5:
                self.condition.notify_all()
        
    def wait(self):
        with self.lock:
            while self.count < 5:
                self.condition.wait()

def worker(resource):
    for i in range(5):
        resource.increment()
        time.sleep(1)
    resource.wait()

resource = SharedResource()
threads = []
for i in range(3):
    t = threading.Thread(target=worker, args=(resource,))
    t.start()
    threads.append(t)

for t in threads:
    t.join()

print("All workers done.")

上面的代码中,SharedResource类中增加了wait方法,并在increment方法中增加了一个判断,当计数器达到5时,调用notify_all方法唤醒所有等待该条件的线程。在worker函数中,每个线程执行5次increment方法后,会调用wait方法等待条件满足。最后的打印"All workers done."会在所有线程都执行完毕并完成条件等待后打印。