Python threading多线程模块的用法(附带实例)
多个进程可以实现多个任务,一个进程内的多个线程(多线程)同样可以实现多个任务。
进程是由若干个线程组成的。一个进程中至少要有一个线程。同一个进程内的多个线程资源共享。线程之间的切换开销比多个进程的切换开销更低。
threading 模块提供的方法有:
首先创建一个 Thread 实例并传入函数,然后调用 start() 即可启动一个新的线程,代码为:
现在假设有一个水池,现有的水量为 1000。有两个线程:
各自重复执行 100000 次,查看水池里的水量。测试代码为:
water 值的计算从 CPU 的角度需要多个步骤,每个步骤的线程都可能被中断,则多个线程就会把同一个对象的内容改乱。为了避免这样的混乱产生,threading 模块提供了多种机制实现线程间的同步。其中,Lock(锁)就是常用的方法之一。
当一个线程修改 water 值时,通过加锁操作可防止其他线程同时进行修改操作,从而避免了 water 值被改错,代码为:
除了 Lock,threading 模块还提供了 RLock、Semaphore 等多种同步机制。
接下来以生产者和消费者为模型,讲解 threading 模块 Queue 的使用。
Queue 用于建立和操作队列,常与 threading 模块一起建立一个简单的线程队列。队列有很多种,根据进出顺序可以分为:
其中,FIFO 是最常用的队列,常用的方法有:
接下来编写一个程序代码:一个线程(生产者)生成数据并将数据加入队列;另一个线程(消费者)去队列中提取这些数据,程序代码保存在文件 queue_thread.py 中,即:
进程是由若干个线程组成的。一个进程中至少要有一个线程。同一个进程内的多个线程资源共享。线程之间的切换开销比多个进程的切换开销更低。
Python threading模块
Python 通过 threading 模块提供了对多线程的支持,使用 threading 模块创建线程的方法有:- 创建一个 Thread 实例,传给它一个函数;
- 创建一个 Thread 实例,传给它一个可调用的类对象;
- 由 Thread 派生一个子类,创建这个子类的实例。
threading 模块提供的方法有:
- start():开始线程的执行;
- run():定义线程的功能函数(一般会被子类重写);
- join(timeout=None):程序挂起,直到线程结束,如果给了 timeout,则最多阻塞 timeout 秒;
- getName():返回线程的名字;
- setName(name):设置线程的名字;
- isAlive():布尔标志,表示这个线程是否还在运行中;
- isDaemon():返回线程的 daemon 标识;
- setDaemon(daemonic):把线程的 daemon 标识设置为 daemonic。
首先创建一个 Thread 实例并传入函数,然后调用 start() 即可启动一个新的线程,代码为:
import time
import threading
def thread1():
while True:
print('thread1 is running')
time.sleep(2)
if __name__ == '__main__':
t1 = threading.Thread(target=thread1, name="")
t1.start()
while True:
print('Main Thread is running')
time.sleep(2)
任何进程都会默认启动一个线程,也就是主线程。执行程序代码后,可以看到主线程和子线程一直处于运行状态,即:
thread1 is running
Main Thread is running
Main Thread is running
thread1 is running
Main Thread is running
thread1 is running
Main Thread is running
Python threading线程同步
主线程和子线程之间相互独立,两者之间没有任何关系。现在假设有一个水池,现有的水量为 1000。有两个线程:
- 一个线程负责往水池里面加水,每次加 1;
- 另一个线程负责从水池里往外抽水,每次抽出的水量也为 1。
各自重复执行 100000 次,查看水池里的水量。测试代码为:
import threading
import time
water = 1000
def add_water():
global water
for i in range(100000):
water += 1
def sub_water():
global water
for i in range(100000):
water -= 1
if __name__ == '__main__':
t_add = threading.Thread(target=add_water, name="")
t_sub = threading.Thread(target=sub_water, name="")
t_add.start()
t_sub.start()
t_add.join()
t_sub.join()
print(water)
多次执行以上程序后,得到的结果为:
1000
-24335
91567
- 计算 water+1,并将计算结果存入临时变量,如 a;
- 将临时变量,也就是 a 赋值给 water。
water 值的计算从 CPU 的角度需要多个步骤,每个步骤的线程都可能被中断,则多个线程就会把同一个对象的内容改乱。为了避免这样的混乱产生,threading 模块提供了多种机制实现线程间的同步。其中,Lock(锁)就是常用的方法之一。
当一个线程修改 water 值时,通过加锁操作可防止其他线程同时进行修改操作,从而避免了 water 值被改错,代码为:
import threading
import time
water = 1000
lock = threading.Lock()
def add_water():
global water
lock.acquire()
for i in range(100000):
water += 1
lock.release()
def sub_water():
with lock:
global water
for i in range(100000):
water -= 1
if __name__ == '__main__':
t_add = threading.Thread(target=add_water, name="")
t_sub = threading.Thread(target=sub_water, name="")
t_add.start()
t_sub.start()
t_add.join()
t_sub.join()
print(water)
以上是使用 Lock 之后的程序代码,多次执行后,水量总是 1000,不会被改乱。除了 Lock,threading 模块还提供了 RLock、Semaphore 等多种同步机制。
Python threading线程间通信
与多进程一样,Python 的 threading 模块同样提供了队列(Queue)、管道(Pipe)等多线程间的通信方式。在 Python 中,队列是线程间最常用的交换数据形式。Queue 是线程安全的自带锁,使用时,不用对队列进行加锁操作。接下来以生产者和消费者为模型,讲解 threading 模块 Queue 的使用。
Queue 用于建立和操作队列,常与 threading 模块一起建立一个简单的线程队列。队列有很多种,根据进出顺序可以分为:
- Queue.Queue(maxsize):FIFO(先进先出队列);
- Queue.LifoQueue(maxsize):LIFO(先进后出队列);
- Queue.PriorityQueue(maxsize):优先度越低的越先出来。
其中,FIFO 是最常用的队列,常用的方法有:
- Queue.qsize():返回队列的大小;
- Queue.empty():如果队列为空,则返回值为 True,反之为 False;
- Queue.full():如果队列满了,则返回值为 True,反之为 False;
- Queue.get([block[,timeout]]):获取队列,timeout 为等待时间;
- Queue.get_nowait():相当 Queue.get(False) 非阻塞;
- Queue.put(item):写入队列,timeout 为等待时间;
- Queue.put_nowait(item):相当 Queue.put(item,False)。
接下来编写一个程序代码:一个线程(生产者)生成数据并将数据加入队列;另一个线程(消费者)去队列中提取这些数据,程序代码保存在文件 queue_thread.py 中,即:
import threading, time
import queue
q = queue.Queue()
def Producer():
n = 0
while n < 5:
n += 1
q.put(n)
print('Producer has created %s' % n)
time.sleep(0.1)
def Consumer():
count = 0
while count < 5:
count += 1
data = q.get()
print('Consumer has used %s' % data)
time.sleep(0.2)
p = threading.Thread(target = Producer, name="")
c = threading.Thread(target = Consumer, name="")
运行结果为:
Producer has created 1
Consumer has used 1
Producer has created 2
Consumer has used 2
Producer has created 3
Producer has created 4
Consumer has used 3
Producer has created 5
Consumer has used 4
Consumer has used 5
ICP备案:
公安联网备案: