GIL全局锁与多进程多线程

GIL全局解释器锁

python的解释器其实有多个版本:Cpython、Jpython等。
重点:
1)GIL不是python的特点,而是Cpython解释器的特点。
2)GIL是保证解释器级别的数据安全。
3)GIL会导致同一个进程下的多个线程无法同时执行。
4)针对不同的数据,还是需要加不同的锁处理。
5)解释型语言的通病:多一个进程下无法利用多核优势。

在Cpython解释器中,GIL是一把互斥锁,用来阻止同一个进程下的多个线程同时执行,即同一个进程下的多个线程无法利用多核优势。因为Cpython解释器中的内存管理(垃圾回收机制)不是线程安全的。

多进程 & 多线程

同一个进程下的多个线程是否有用要看具体情况:
单核:假如有四个任务(IO密集型/计算密集型)
多核:假如有四个任务(IO密集型/计算密集型)

计算密集型(cpu切换不频繁)

单核:
 多进程:额外的消耗资源;
 多线程:节省开销;
多核:
 多进程:总耗时/核数量;
 多线程:总耗时+切换时间;

IO密集型(cpu切换频繁)

多核:
 多进程:相对浪费资源;
 多线程:更加节省资源;

死锁与递归锁

虽然知道抢锁必须释放锁,单也容易出现死锁现象。
递归锁的特点:
1)可以被连续地acquire和release,但是只能被第一个抢到这把锁的人执行此操作。
2)它的内部有一个计数器,每acquire一次计数加一,每release一次计数减一,只要计数不为0,那么其他人无法抢到该锁。

信号量

信号量在不同的阶段可能对应不同的技术点。
在并发编程中信号量指的是锁,如果我们将互斥锁比喻成一个厕所的话,那么信号量就相当于多个厕所。

event事件

一些进程/线程需要等待另外一些进程/线程程序运行完毕之后才能运行,类似于发射信号一样。

线程池和进程池

TCP服务端实现并发的效果:每来一个人就开设一个进程或线程去处理(旧)。无论开设进程还是线程,都需要消耗资源,只不过开设线程的消耗比开设进程小一点。但我们不能无限制地开设进程和线程,因为计算机硬件资源跟不上,硬件的开发速度远远赶不上软件,我们的宗旨是保证计算机硬件能够正常工作的情况下最大限度地利用它。

池地概念:池是用来保证硬件安全的情况下最大限度地利用计算机,它降低了程序运行效率,但是保证了安全,从而让程序正常运行。

进程池和线程池的使用:

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time
import os


pool = ThreadPoolExecutor() # 括号内可以传数字,不传的话默认会开设当前计算机cpu个数的线程,如果传数字5,池子里会固定5个线程,这5个线程不会出现重复创建和销毁。
def task(n):
    print(n)
    time.sleep(2)
    retrun n ** n

def call_back(n):
    print('>>>call_back:', n.result())


# pool.submit(task, 1) # 朝池子中提交任务,为异步提交
t_list = []
for i in rage(20): # 向池子中提交20个任务
    res = pool.submit(task, i).add_done_callback(call_back)
    t_list.append(res)

for t in t_list:
    print('>>>:', t.result())
# 等待线程池中所有的任务执行完毕后再继续往下执行

pool = ProcessPoolExecutor()
# 异步提交任务的返回结果,应该通过回调机制来获取

协程基本原理

进程:资源单位
线程:执行单位
协程:单线程下实现并发的效果(程序员自己在代码层面监测所有的IO操作,一旦遇IO,就在代码级别完成切换,这样给CPU的感觉是程序一直在运行没有IO,从而提升程序的运行效果。)
多道技术:切换 + 保存状态
cpu切换:1)程序遇到IO;2)程序长时间占用。
切换不一定提升效率,也有可能降低效率(IO切换提升,非IO切换降低)
保存状态:保存上一次我执行的状态,下一次来接着上一次的操作继续往下执行。

gevent模块:gevent模块本身无法检测常见的一些IO操作,在使用的时候需要额外导入一句话。

from gevent import monkey; monkey.patch_all()

def heng():
    print('heng')
    time.sleep(2)
    print('heng')

def ha():
    print('ha')
    time.sleep(3)
    print('ha')

start_time = time.time()
g1 = spawn(heng)
g2 = spawn(ha)
g1.join()
g2.join()
print(time.time() - start_time) # 3

你可能感兴趣的:(GIL全局锁与多进程多线程)