基于线程和进程的深入研究

2019-05-10 06:00:13来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

cpython中的GIL解释器锁

基于对GIL解释器锁的问题,我们先来看一下官方文档给出的解释:

 1 """
 2 
 3       In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple
 4 native threads from executing Python bytecodes at once. This lock is necessary mainly
 5 because CPython’s memory management is not thread-safe. (However, since the GIL
 6 exists, other features have grown to depend on the guarantees that it enforces.)
 7 
 8 """
 9 我们能提炼出以下几点:
10 1.GIL是一个互斥锁:保证数据的安全(以牺牲效率来换取数据的安全)
11 2.阻止同一个进程内多个线程同时执行(不能并行但是能够实现并发)
12 3.并发:看起来像同时进行的
13 4.GIL全局解释器存在的原因是因为Cpython解释器的内存管理不是线程安全的

 

这里不同于pycharm的垃圾回收机制:1.引用计数 2.标记清除 3.分代回收

也就是说,在同一进程下的多个线程是不可能实现并行的但是可以实现并发;相反多个进程下的线程是可以实现并行的。

基于这点,你会问:我曹,python连多线程抖实现不了,是不是太low了啊?我的回答是:不是的。对于多个进程的多线程的并行实现是毋庸置疑的,在同一个进程下的并行分为两种情况:

1.基于计算密集型

    首先在单核情况下:基于计算的使用多线程较好,因为在相同的进程数下,多线程消耗的资源少。

    在多核的情况下:开四个进程可能需要10s左右,而开四个线程需要40s左右。

2.基于IO密集型

  首先在单核情况下;多线程比较好一点

  在多核的情况下:多线程比较好一点

1.基于计算密集型

 1 # 导入相关的模块
 2 from multiprocessing import Process
 3 from theading import Thread
 4 import time, os
 5 
 6 
 7 # 定义计算过程
 8 def work():
 9     res = 0
10     for i in range(100):
11         res *= i
12 
13 if __name__=='__mian__':
14     
15     # 本机的硬件基础
16     print(os.cpu_count)  # 本机的cpu核心数为4
17     lis = []
18     start = time.time()
19     for i in range(8):
20         p = Process(target = work) # 创建的线程这里不做演示,类似的
21         lis.append(p)
22        p.start()
23     
24     for i in lis:
25         i.join()
26     end = time.time()
27     # 打印输出使用的时间
28     print('use time is :%s' %(end - start))

2.基于IO的型

from multiprocessing import Process
from threading import Thread
import os, time


# def work():
#     res = 0
#     for i in range(100):
#         res += i


# 基于IO型
def sleep():
    time.sleep(3)

if __name__ == '__main__':
    lis = []
    start = time.time()
    for i in range(8):
        p = Process(target=sleep)
        # p = Thread(target=sleep)
        lis.append(p)
        p.start()
    for j in lis:
        j.join()
    end = time.time()
    print('use time is : %s' % (end - start))

GIL解释器锁和互斥锁的对比

大方面:GIL解释器锁针对的是解释器;互斥锁针对的是操作的数据。

 

 1 from threading import Thread,Lock
 2 import time
 3 
 4 mutex = Lock()
 5 
 6 n = 100
 7 
 8 def task():
 9     global n
10     mutex.acquire()
11     tmp = n
12     time.sleep(0.1)
13     n = tmp - 1
14     mutex.release()
15 
16 t_list = []
17 for i in range(100):
18     t = Thread(target=task)
19     t.start()
20     t_list.append(t)
21 
22 for t in t_list:
23     t.join()
24 
25 print(n)
26 
27 """
28 对于不同的数据,要想保证安全,需要加不同的锁处理
29 GIL并不能保证数据的安全,它是对Cpython解释器加锁,针对的是线程
30 保证的是同一个进程下多个线程之间的安全
31 """

 

死锁和递归锁

 1 from threading import Thread,Lock,RLock
 2 import time
 3 
 4 """
 5 自定义锁一次acquire必须对应一次release,不能连续acquire
 6 递归锁可以连续的acquire,每acquire一次计数加一:针对的是第一个抢到我的人
 7 """
 8 import random
 9 #
10 # mutexA = Lock()
11 # mutexB = Lock()
12 mutexA = mutexB = RLock()  # 抢锁之后会有一个计数 抢一次计数加一 针对的是第一个抢到我的人
13 
14 
15 class MyThead(Thread):
16     def run(self):
17         self.func1()
18         self.func2()
19 
20     def func1(self):
21         mutexA.acquire()
22         print('%s 抢到A锁了'%self.name)
23         mutexB.acquire()
24         print('%s 抢到B锁了' % self.name)
25         mutexB.release()
26         print('%s 释放了B锁'%self.name)
27         mutexA.release()
28         print('%s 释放了A锁'%self.name)
29 
30     def func2(self):
31         mutexB.acquire()
32         print('%s 抢到了B锁'%self.name)
33         time.sleep(1)
34         mutexA.acquire()
35         print('%s 抢到A锁了' % self.name)
36         mutexA.release()
37         print('%s 释放了A锁' % self.name)
38         mutexB.release()
39         print('%s 释放了B锁' % self.name)
40 
41 
42 for i in range(100):
43     t = MyThead()
44     t.start()

 

线程Queue

import queue

# 1.普通q
# 2.先进后出q
# 3.优先级q


# queue包含的有Queue,LifoQueue,PriorityQueue

# q=queue.Queue(3)
# q.put(1)
# q.put(2)
# q.put(3)
# print(q.get())
# print(q.get())
# print(q.get())

# q = queue.LifoQueue(5)
# q.put(1)
# q.put(2)
# q.put(3)
# q.put(4)
# print(q.get())



# 优先级q
# q = queue.PriorityQueue()
# q.put((10,'a'))
# q.put((-1,'b'))
# q.put((100,'c'))
# print(q.get())
# print(q.get())
# print(q.get())

信号量

 

 1 from threading import Thread,Semaphore
 2 import time
 3 import random
 4 sm = Semaphore(5)  # 五个厕所五把锁
 5 # 跟你普通的互斥锁区别在于,普通的互斥锁是独立卫生间,所有人抢一把锁
 6 # 信号量 公共卫生间 有多个坑,所有人抢多把锁
 7 
 8 
 9 
10 def task(name):
11     sm.acquire()
12     print('%s正在蹲坑'%name)
13     # 模拟蹲坑耗时
14     time.sleep(random.randint(1,5))
15     sm.release()
16 
17 
18 if __name__ == '__main__':
19     for i in range(20):
20         t = Thread(target=task,args=('伞兵%s号'%i,))
21         t.start()

 

 


原文链接:https://www.cnblogs.com/wanglei957/p/10832186.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:Python和Java的语法对比,语法简洁上python的确完美胜出

下一篇:Django中配置自定义日志系统