Python 多线程
参考自:https://morvanzhou.github.io/tutorials/python-basic/basic/
多线程模块的一些基本操作:
首先导入模块:
import threading
获得已激活的线程数:
threading.active_count()
查看所有线程信息:
threading.enumerate()
输出的结果是一个<_MainThread(...)>
带多个<Thread(...)>
。
添加线程,threading.Thread()接收参数target代表这个线程要完成的任务,需要自行定义,name可以给线程定义名字
def thread_job(): print('This is a thread of %s' % threading.current_thread()) def main(): thread = threading.Thread(target=thread_job,name = 'T1') # 定义线程 thread.start() # 让线程开始工作 if __name__ == '__main__': main()
join()功能
主要是为了让多线程按一个既定的顺序的执行。
不加 join() 的结果
我们让 T1
线程工作的耗时增加:
import threading import time def thread_job(): print("T1 start\n") for i in range(10): time.sleep(0.1) # 任务间隔0.1s print("T1 finish\n") added_thread = threading.Thread(target=thread_job, name='T1') added_thread.start() print("all done\n")
预想中输出的结果是否为:
T1 start
T1 finish
all done
但实际却是:
T1 start
all done
T1 finish
加入 join() 的结果 ¶
def T1_job(): print("T1 start\n") for i in range(10): time.sleep(0.1) print("T1 finish\n") def T2_job(): print("T2 start\n") print("T2 finish\n") thread_1 = threading.Thread(target=T1_job, name='T1') thread_2 = threading.Thread(target=T2_job, name='T2') thread_1.start() # 开启T1 thread_2.start() # 开启T2 thread_2.join() thread_1,join() print("all done\n")
T1 start
T2 start
T2 finish
T1 finish
all done
储存进程结果 Queue
代码实现功能,将数据列表中的数据传入,使用四个线程处理,将结果保存在Queue
中,线程执行完后,从Queue
中获取存储的结果.
导入线程,队列的标准模块
import threading import time from queue import Queue
定义一个被多线程调用的函数
函数的参数是一个列表l和一个队列q
,函数的功能是,对列表的每个元素进行平方计算,将结果保存在队列中
def job(l,q): for i in range (len(l)): l[i] = l[i]**2 q.put(l) #多线程调用的函数不能用return返回值
定义一个多线程函数
在多线程函数中定义一个Queue
,用来保存返回值,代替return
,定义一个多线程列表,初始化一个多维数据列表,用来处理:
def multithreading(): q =Queue() #q中存放返回值,代替return的返回值 threads = [] data = [[1,2,3],[3,4,5],[4,4,4],[5,5,5]]
在多线程函数中定义四个线程,启动线程,将每个线程添加到多线程的列表中
for i in range(4): #定义四个线程 t = threading.Thread(target=job,args=(data[i],q)) #Thread首字母要大写,被调用的job函数没有括号,只是一个索引,参数在后面 t.start()#开始线程 threads.append(t) #把每个线程append到线程列表中
分别join
四个线程到主线程
for thread in threads: thread.join()
定义一个空的列表results
,将四个线程运行后保存在队列中的结果返回给空列表results
results = [] for _ in range(4): results.append(q.get()) #q.get()按顺序从q中拿出一个值 print(results)
完整的代码
import threading import time from queue import Queue def job(l,q): for i in range (len(l)): l[i] = l[i]**2 q.put(l) def multithreading(): q =Queue() threads = [] data = [[1,2,3],[3,4,5],[4,4,4],[5,5,5]] for i in range(4): t = threading.Thread(target=job,args=(data[i],q)) #参数列表 args t.start() threads.append(t) for thread in threads: thread.join() results = [] for _ in range(4): results.append(q.get()) print(results) if __name___=='__main__': multithreading()
最后运行结果为:
[[1, 4, 9], [9, 16, 25], [16, 16, 16], [25, 25, 25]]
线程锁 Lock
不使用 Lock 的情况
函数一:全局变量A的值每次加1,循环10次,并打印
def job1(): global A for i in range(10): A+=1 print('job1',A)
函数二:全局变量A的值每次加10,循环10次,并打印
def job2(): global A for i in range(10): A+=10 print('job2',A)
主函数:定义两个线程,分别执行函数一和函数二
if __name__== '__main__': A=0 t1=threading.Thread(target=job1) t2=threading.Thread(target=job2) t1.start() t2.start() t1.join() t2.join()
完整代码:
import threading def job1(): global A for i in range(10): A+=1 print('job1',A) def job2(): global A for i in range(10): A+=10 print('job2',A) if __name__== '__main__': lock=threading.Lock() A=0 t1=threading.Thread(target=job1) t2=threading.Thread(target=job2) t1.start() t2.start() t1.join() t2.join()
运行结果
job1job2 11 job2 21 job2 31 job2 41 job2 51 job2 61 job2 71 job2 81 job2 91 job2 101 1 job1 102 job1 103 job1 104 job1 105 job1 106 job1 107 job1 108 job1 109 job1 110
可以看出,打印的结果非常混乱
使用 Lock 的情况
lock在不同线程使用同一共享内存时,能够确保线程之间互不影响,使用lock的方法是, 在每个线程执行运算修改共享内存之前,执行lock.acquire()
将共享内存上锁, 确保当前线程执行时,内存不会被其他线程访问,执行运算完毕后,使用lock.release()
将锁打开, 保证其他的线程可以使用该共享内存。
函数一和函数二加锁
def job1(): global A,lock lock.acquire() for i in range(10): A+=1 print('job1',A) lock.release() def job2(): global A,lock lock.acquire() for i in range(10): A+=10 print('job2',A) lock.release()
主函数中定义一个Lock
if __name__== '__main__': lock=threading.Lock() A=0 t1=threading.Thread(target=job1) t2=threading.Thread(target=job2) t1.start() t2.start() t1.join() t2.join()
完整的代码
import threading def job1(): global A,lock lock.acquire() for i in range(10): A+=1 print('job1',A) lock.release() def job2(): global A,lock lock.acquire() for i in range(10): A+=10 print('job2',A) lock.release() if __name__== '__main__': lock=threading.Lock() A=0 t1=threading.Thread(target=job1) t2=threading.Thread(target=job2) t1.start() t2.start() t1.join() t2.join()
运行结果
从打印结果来看,使用lock
后,一个一个线程执行完。使用lock
和不使用lock
,最后打印输出的结果是不同的。