共享内存和锁
1. 锁
在多线程和多进程中,涉及到每个线程或者进程对某个资源的访问,这就需要设置锁来防止两个进程或者线程同时访问一个资源从而导致的数据风险问题
-
多线程中的锁
def fun(lock, value): with lock: time.sleep(2) with open('test.txt', 'a') as f: f.write(value) lock = td.Lock() # 创建一个普通锁 rlock = td.RLock() # 创建一个递归锁 th1 = td.Thread(target=fun, args=(lock, 1)) th2 = td.Thread(target=fun, args=(lock, 2)) th1.start() th2.start()
-
多线程编程中使用
threading.Lock()
创建一个锁,需要把锁作为参数,在创建线程时使用args
传入到函数中。 -
with lock
:语句块是加锁模块,当一个进程获取到lock权限之后,再有进程想要获取lock就会进入阻塞状态,直到锁释放。使用with
相当于下述语法lock.acquire() # 获取 / 语句块 / lock.release() # 释放
-
Lock
和RLock
:Lock是普通锁,只允许进程获取一次,RLock是递归锁允许同一个进程连续获取很多次,RLock的应用主要是在递归编程上。下面的实例中,如果使用的是lock
锁,那么当前进程递归进入到函数中时将会由于lock
不可获取而锁死。def fun(rlock): with rlock: fun(rlock)
-
-
多进程中的锁
lock = mp.Lock() rlock = mp.RLock()
- 锁的创建方式如上所示,具体的用法同多线程编程中完全相同。
- 需要注意的是,使用锁的时候,配合map传入线程锁,会报错!!!!不知道为啥
-
在多进程中,使用
mp.Lock()
创建的锁不能配合map使用,如下所示的代码运行会报错!!会报错if __name__ == '__main__': data = pd.read_csv("./data/phen.csv") data = data['phen'] data.dropna(inplace=True) l = mp.Lock() # 使用mp创建锁 ls = [(data, bins, l) for bins in [10, 20, 30, 40, 50, 60]] with mp.Pool(mp.cpu_count()) as pool: pool.starmap(fun, ls) # 使用map 或者 starmap将锁传入函数 会报错 # 使用 mp.Process 的方式不会报错 p = mp.Process(target=fun, args = (value, lock))
如果要将锁配合map使用,需要使用
Manager
创建锁!!!!1if __name__ == '__main__': data = pd.read_csv("./data/phen.csv") data = data['phen'] data.dropna(inplace=True) with mp.Manager() as manager: l = manager.Lock() # 使用manager.Lock()创建一个可以在进程间传递的锁!!! ls = [(data, bins, l) for bins in [10, 20, 30, 40, 50, 60]] with mp.Pool(mp.cpu_count()) as pool: pool.starmap(fun, ls)
2. 共享内存
-
多线程编程中的共享内存:线程共享进程的内存空间,所以一个python脚本可以是可以之间通过访问和修改 全局变量 实现数据共享的
counter = 0 lock = threading.Lock() def fun(lock): global counter with lock: counter += 1 for _ in range(10): threading.Thread(target=fun, args=(lock, )).start()
- 上述示例中,创建的进程都会访问counter变量,实现数据共享,并通过锁来保证数据共享时的安全问题
-
多进程编程中的共享内存:每个进程都有自己独立的内存空间,不能直接通过全局变量的形式共享内存
-
共享变量的创建以及使用
value = mp.Value('i', 0) # 创建一个整型的共享变量 value 初值为0 v = value.value # 使用value方法获取值 array = mp.Array('i', 10) # 创建一个共享变量,视作10个元素的一维列表 ,每个元素为0 v = array[0] # 可以直接通过索引获取值 for v in array: print(v) # 可以通过遍历获取值
mp.Value
:创建一个共享变量,i
表示是整型,0是设置的初始值mp.Array
:创建一个一维共享列表,i
表示每个元素是整型,长度为10
-
共享变量的访问和修改也需要配合锁来使用
def fun(lock, value): with lock: value.value += 1 if __name__ == "__main__": value = mp.Value('i', 0) lock = mp.Lock() for _ in range(10): p = mp.Process(target=fun, args = (value, lock)) p.start()
-
这里需要理解的一件事儿是:在多进程中使用全局变量,每个进程访问前都是0,结束后都是1,并不能做到累计加和的作用
value = 0 def fun(lock, value): global value with lock: value += 1 print(value) # 十个进程的输出都是 1 if __name__ == "__main__": value = mp.Value('i', 0) lock = mp.Lock() for _ in range(10): p = mp.Process(target=fun, args = (lock, )) p.start()
-
-