📜  Python的并发性-线程(1)

📅  最后修改于: 2023-12-03 15:19:34.563000             🧑  作者: Mango

Python的并发性-线程

线程是什么?

线程是程序执行的一条路径,一个进程可以有多个线程同时执行不同的任务,利用了多核处理器的优势,提高了程序的执行效率。Python的内置模块 threading 可以方便地创建、操作线程。

创建线程

使用 threading 模块的 Thread 类创建一个新的线程,示例如下:

import threading

def worker():
    """线程函数"""
    print('This is a new thread.')

# 创建线程
t = threading.Thread(target=worker)
# 启动线程
t.start()

该代码会输出一行文字:

This is a new thread.

其中,target 参数指定线程函数,start 方法启动线程。注意,线程并不是马上运行,而是等待 CPU 调度。

线程同步

多个线程共享同一份数据时,可能会出现数据不一致、竞争条件的问题。Python 的 threading 模块提供了一些同步工具来解决这些问题。

线程之间竞争一份数据时,可以使用锁来保证同一时刻只有一个线程能够访问数据。

import threading

# 共享数据
a = 0
# 创建互斥锁
lock = threading.Lock()

def worker():
    """线程函数"""
    global a, lock
    for i in range(1000000):
        # 获取锁
        lock.acquire()
        a += 1
        # 释放锁
        lock.release()

# 创建线程
t1 = threading.Thread(target=worker)
t2 = threading.Thread(target=worker)
# 启动线程
t1.start()
t2.start()
# 等待线程结束
t1.join()
t2.join()

# 输出结果
print(a)

由于两个线程对 a 进行了 100 万次的加一操作,最终输出的结果应该是 2 百万。如果不使用锁,输出结果会小于 2 百万,因为两个线程会竞争访问 a

信号量

信号量用于限制同时访问共享资源的线程数量。

import threading

# 共享资源
s = threading.Semaphore(2)

def worker():
    """线程函数"""
    global s
    with s:
        print('Thread {} is running.'.format(threading.current_thread().name))

# 创建线程
t1 = threading.Thread(target=worker, name='A')
t2 = threading.Thread(target=worker, name='B')
t3 = threading.Thread(target=worker, name='C')

# 启动线程
t1.start()
t2.start()
t3.start()

使用 threading.Semaphore(2) 创建了一个限制同时访问资源的数量为 2 的信号量。输出结果是:

Thread A is running.
Thread B is running.
Thread C is running.

由于只有两个线程能够获得信号量,因此线程 C 需要等待线程 A 或线程 B 中的一个结束后才能开始运行。

线程池

线程池是一组预先创建的线程,可以提高线程的复用性,减少线程的创建和销毁所带来的开销,提高程序性能。

Python 的 concurrent.futures 模块提供了线程池和进程池的实现。下面是一个使用 concurrent.futures.ThreadPoolExecutor 实现线程池的例子:

import concurrent.futures

def worker(index):
    """线程函数"""
    return 'Task {} is done.'.format(index)

# 创建线程池
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
    # 提交任务
    futures = [executor.submit(worker, i) for i in range(10)]
    # 获取结果
    for future in concurrent.futures.as_completed(futures):
        print(future.result())

max_workers=4 指定线程池中最多有 4 个线程同时执行任务。我们提交了 10 个任务,并用 as_completed 方法获取执行结果。

执行结果:

Task 5 is done.
Task 6 is done.
Task 7 is done.
Task 8 is done.
Task 9 is done.
Task 0 is done.
Task 1 is done.
Task 2 is done.
Task 3 is done.
Task 4 is done.
总结

Python 的线程模块 threading 提供了创建、操作线程的接口,多个线程之间共享数据时需要使用同步工具,例如锁、信号量、条件变量等。使用线程池可以提高程序性能,减少线程创建和销毁所带来的开销。