Python 多线程(Threading)

Python 多线程(Threading)

仅供个人学习
来源于 莫凡Python:https://mofanpy.com/tutorials/python-basic/basic/ 侵删

什么是多线程 Threading

多线程是加速程序计算的有效方式,使用 threading 模块

添加线程 Thread

import threading

# 获取已激活的线程数
threading.active_count()
>>> 2

# 查看所有线程信息
threading.enumerate()
>>> [<_MainThread(MainThread, started 140736011932608)>, <Thread(SockThread, started daemon 123145376751616)>]

# 查看正在运行的线程
threading.current_thread()

# 添加线程 threading.Thread()接收参数target代表这个线程要完成的任务,需自行定义
def thread_job():
    print('This is a thread of %s' % threading.current_thread())

def main():
    thread = threading.Thread(target=thread_job,)   # 定义线程 
    thread.start()  # 让线程开始工作
    
if __name__ == '__main__':
    main()

join 功能

不加join完全取决于两个线程的执行速度。加入join对线程进行控制。

例:t1.join()等待t1线程结束后,在往下执行。

存储进程结果 Queue

# 导入线程、队列的标准模块
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)	# 多线程调用的函数不能用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到线程列表中
	for thread in threads:
    	thread.join()
    results = []
	for _ in range(4):
    	results.append(q.get())  #q.get()按顺序从q中拿出一个值
	print(results)
if __name__=='__main__':
    multithreading()
    
# 结果
>>> [[1, 4, 9], [9, 16, 25], [16, 16, 16], [25, 25, 25]]

GIL 不一定有效率

python 的多线程 threading 有时候并不是特别理想. 最主要的原因是就是, Python 的设计上, 有一个必要的环节, 就是 Global Interpreter Lock (GIL). 这个东西让 Python 还是一次性只能处理一个东西.

GIL:

  尽管Python完全支持多线程编程, 但是解释器的C语言实现部分在完全并行执行时并不是线程安全的。 实际上,解释器被一个全局解释器锁保护着,它确保任何时候都只有一个Python线程执行。 GIL最大的问题就是Python的多线程程序并不能利用多核CPU的优势 (比如一个使用了多个线程的计算密集型程序只会在一个单CPU上面运行)。

  在讨论普通的GIL之前,有一点要强调的是GIL只会影响到那些严重依赖CPU的程序(比如计算型的)。 如果你的程序大部分只会涉及到I/O,比如网络交互,那么使用多线程就很合适, 因为它们大部分时间都在等待。实际上,你完全可以放心的创建几千个Python线程, 现代操作系统运行这么多线程没有任何压力。

线程锁 Lock

lock在不同线程使用同一共享内存时,能够确保线程之间互不影响,使用lock的方法是, 在每个线程执行运算修改共享内存之前,执行lock.acquire()将共享内存上锁, 确保当前线程执行时,内存不会被其他线程访问,执行运算完毕后,使用lock.release()将锁打开, 保证其他的线程可以使用该共享内存。

# 未加锁输出结果
"""
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
"""

# 加锁代码
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()
    
# 加锁结果
"""
job1 1
job1 2
job1 3
job1 4
job1 5
job1 6
job1 7
job1 8
job1 9
job1 10
job2 20
job2 30
job2 40
job2 50
job2 60
job2 70
job2 80
job2 90
job2 100
job2 110
"""
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值