1.多线程基础知识
使用Python的Threading库可以实现多线程,先来介绍基本的代码:
# 建立线程,将target指定为要执行的function,name就是设定的线程名称,若要传入参数,可以设定args,设定格式一定要是Tuple(变量名1,变量名2,...)
threading.Thread(target=function, name="Thread名字", args=tuple(,))
# 开始执行指定的线程,start前面要放指定的线程名称
<Thread>.start()
# 将主线程暂停,等待指定的线程结束,join前面要放指定的线程名
<Thread>.join()
# 查看目前有多少个线程
threading.active_count()
# 查看目前使用线程的信息
threading.enumerate()
# 查看目前在哪个线程中
threading.current_thread()
接下来示范一些简单的执行线程的操作
- 建立线程
使用threading.Thread(target=thread_job)建立一个线程,并用start开始执行
import threading
def thread_job():
print("abc")
added_thread = threading.Thread(target=thread_job)
added_thread.start()
# =========output========
# abc
- 等待指定线程结束
使用join()将主线程暂停,等待指定的线程结束,主线程才会结束。以下范例为未加及加了join的代码与结果比较
# 未加join
import threading
import time
def thread_first_job(x):
time.sleep(0.1)
print("This is the first thread", x)
def thread_second_job(x):
print("This is the second thread", x)
# 若thread要传入参数格式指定为(x,)
first_thread = threading.Thread(target=thread_first_job, args=("Hi",))
second_thread = threading.Thread(target=thread_second_job, args=("Hello",))
first_thread.start()
second_thread.start()
print("all done")
# --------output--------
# This is the second thread Hello
# all done
# This is the first thread Hi
# 加入join()
import threading
import time
def thread_first_job(x):
time.sleep(0.1)
print("This is the first thread", x)
def thread_second_job(x):
print("This is the second thread", x)
# 若thread要传入参数格式指定为(x,)
first_thread = threading.Thread(target=thread_first_job, args=("Hi",))
second_thread = threading.Thread(target=thread_second_job, args=("Hello",))
first_thread.start()
second_thread.start()
# 使用join等待first_thread执行完毕
first_thread.join()
print("all done")
# --------output--------
# This is the second thread Hello
# This is the first thread Hi
# all done
未加join()的输出并不会等待first thread输出再进行从下一步,而加了join()后则会等待输出first thread
- setDaemon(bool)
若希望再主线程执行完毕后,不管其他的Thread是否已经执行完毕,都强制跟主线程一起结束,必须写在start()之前,默认值为False。
import threading
import time
def thread_first_job(x):
time.sleep(5)
print("This is the first thread ", x)
def thread_second_job(x):
print("This is the second thread ", x)
first_thread = threading.Thread(target = thread_first_job, args=("Hi",))
second_thread = threading.Thread(target = thread_second_job, args=("Hello",))
second_thread.setDaemon(True)
first_thread.start()
second_thread.start()
2.多线程的同步机制(Synchronized)
同步机制(Synchronized)有以下几种:互斥量(Mutex),讯号量(Semaphore),条件变量(Condition Variable),原子变量(Atomic),队列(Queue),事件(Event)
- Queue()
Thread无法回传值,所以要使用Queue.put()将要传回的值存入Queue,再用Queue.get()取出
import threading
from queue import Queue
# 将要回传的值存入Queue
def thread_job(data, q):
for i in range(len(data)):
data[i] = data[i]*2
q.put(data)
def multithread():
data = [[1, 2, 3], [4, 5, 6]]
q = Queue()
all_thread = []
# 使用multi-thread
for i in range(len(data)):
thread = threading.Thread(target=thread_job, args=(data[i], q))
thread.start()
all_thread.append(thread)
# 等待全部Thread执行完毕
for t in all_thread:
t,join()
# 使用q.get()取出要传回的值
result = []
for _ in range(len(all_thread)):
result.append(q.get())
print(result)
multithread()
# ------output------
# [[2, 4, 6], [8, 10, 12]]
- Lock()
当同时有几个Thread要用到同一个数据时候,为了不发生Race Condition的现象,需要使用lock.acquire()以及lock.release()来将其锁定住,不让其他Thread执行。
import threading
def thread_first_job():
global a, lock
lock.acquire()
for _ in range(3):
a += 1
print("This is the first thread", a)
lock.release()
def thread_second_job():
global a, lock
lock.acquire()
for _ in range(3):
a -= 1
print("This is the second thread", a)
lock.release()
a = 0
lock = threading.Lock()
first_thread = threading.Thread(target=thread_first_job)
second_thread = threading.Thread(target=thread_second_job)
first_thread.start()
second_thread.start()
first_thread.join()
second_thread.join()
#----------output----------
# 会先由first_thread执行,执行完后才会交给second_thread
# This is the first thread 1
# This is the first thread 2
# This is the first thread 3
# This is the second thread 2
# This is the second thread 1
# This is the second thread 0
- Semaphore
Semaphore跟Lock类似,但是Semaphore多了计数器的功能,可以允许多个线程同时执行
import threading
def thread_first_job():
global a
# 取得旗标
semaphore.acquire()
for _ in range(3):
a += 1
print("This is the first thread", a)
semaphore.release()
def thread_second_job():
global a
# 取得旗标
semaphore.acquire()
for _ in range(3):
a -= 1
print("This is the second thread", a)
semaphore.release()
a = 0
# 设定旗标计数器为2
semaphore = threading.Semaphore(2)
first_thread = threading.Thread(target=thread_first_job)
second_thread = threading.Thread(target=thread_second_job)
first_thread.start()
second_thread.start()
first_thread.join()
second_thread.join()
#----------output----------
# first_thread与second_thread会同时进行
# This is the first thread 1
# This is the second thread 0
# This is the second thread -1
# This is the second thread -2
# This is the first thread -1
# This is the first thread 0
- RLock
RLock跟Lock类似,但RLock可允许同一个线程重复取得锁定的使用权,使用acquire取得rlock,release释放rlock
import threading
rlock = threading.RLock()
rlock.acquire()
rlock.acquire()
rlock.release()
rlock.release()
- Condition
提供比Lock,RLock更高级的功能;等待wait(),唤醒等待中的线程notify(),唤醒所有等待中的线程notifyAll(),也提供了acquire,release方法,threading.Condition在内部维护一个锁对象(默认是RLock),可以在创建Condition对象的时候把锁对象作为参数传入
import threading
def thread_first_job():
global a, cond
# 取得 lock
cond.acquire()
print("Acquire the condition lock")
# 线程进入等待状态
if a == 0:
print("Wait…")
cond.wait()
# 唤醒线程
print("Notify to wake up…")
cond.notify()
for _ in range(3):
a += 1
print("This is the first thread ", a)
# 释放lock
cond.release()
def thread_second_job():
global a, cond
# 取得 lock
cond.acquire()
# 唤醒线程
cond.notify()
a += 1
# 释放 lock
cond.release()
a = 0
cond = threading.Condition()
first_thread = threading.Thread(target = thread_first_job)
second_thread = threading.Thread(target = thread_second_job)
first_thread.start()
second_thread.start()
first_thread.join()
second_thread.join()
# ====== output ======
# Acquire the condition lock
# Wait...
# Notify to wake up...
# This is the first thread 2
# This is the first thread 3
# This is the first thread 4
- Event
用于线程间的通信,发送线程设置的信号,若信号为True,其他等待的线程接收到信号后会被唤醒。提供设置信号event.set(),等待信号event.wait(),清除信号event.clear()功能
import threading
import time
def thread_first_job():
global a
# 线程等待状态
print("Wait…")
event.wait()
for _ in range(3):
a += 1
print("This is the first thread ", a)
a = 0
# 创建 event
event = threading.Event()
first_thread = threading.Thread(target = thread_first_job)
first_thread.start()
time.sleep(3)
# 唤醒等待状态的线程
print("Wake up the thread…")
event.set()
first_thread.join()
# ====== output ======
# Wait...
# Wake up the thread...
# This is the first thread 1
# This is the first thread 2
# This is the first thread 3
参考目录
https://medium.com/ching-i/%E5%A4%9A%E5%9F%B7%E8%A1%8C%E7%B7%92-python-threading-52e1dfb3d5c9