线程互斥锁+GIL全局解释器锁+进程池与线程池+互斥锁与递归锁

"""
# 锁:牺牲程序的运行效率换取数据的安全
1.将并发变成串行
2.降低了程序的运行效率但是提高数据的安全性
"""
from multiprocessing import Process,Lock
# from threading import Thread,Lock
import time
n = 100


def task(mutex):
global n
mutex.acquire() # 抢锁
temp = n
time.sleep(0.1)
n = temp - 1
mutex.release() # 释放锁

if __name__ == '__main__':
mutex = Lock()
t_list = []
for i in range(10):
# t = Thread(target=task,args=(mutex,))
t = Process(target=task,args=(mutex,))
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(n)


"""
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple
native threads from executing Python bytecodes at once. This lock is necessary mainly
because CPython’s memory management is not thread-safe. (However, since the GIL
exists, other features have grown to depend on the guarantees that it enforces.)
"""
"""
1.GIL全局解释锁只在Cpython解释器上才有
2.GIL全局解释锁本质也是一把互斥锁
3.GIL全局解释锁用来锁住同一个进程下多个线程的运行
4.因为内存管理不是线程安全的

内存管理(垃圾回收机制)
1.引用计数
2.标记清除
3.分代回收

1.cpython解释器下python的同一个进程下的多线程真的一点用没有吗?
你不能够直接下结论,应该分任务的类型来讨论
四个任务都是计算密集型的 10s
多线程 40s+
多进程 10s+
四个任务都是IO密集型的 10s
多进程
1.申请内存空间
2.执行代码
多线程(优势的)

结论:
当你的任务是以计算为主那么你可以开多进程
当你的任务是以IO为主的那么你可以开多线程

"""

"""
# 计算密集型 多进程
from multiprocessing import Process
from threading import Thread
import os, time


def work():
res = 0
for i in range(100000000):
res *= i


if __name__ == '__main__':
l = []
print('本机的核数是:',os.cpu_count()) # 本机为8核
start = time.time()
for i in range(12):
# p = Process(target=work) # 耗时16.573697090148926秒多
p=Thread(target=work) #耗时48.35181450843811s多
l.append(p)
p.start()
for p in l:
p.join()
stop = time.time()
print('run time is %s' % (stop - start))

"""

# IO密集型 多线程
from multiprocessing import Process
from threading import Thread
import threading
import os, time


def work():
time.sleep(2)


if __name__ == '__main__':
l = []
print(os.cpu_count()) # 本机为8核
start = time.time()
for i in range(20):
p = Process(target=work) # 耗时20.29075288772583s多,大部分时间耗费在创建进程上
# p = Thread(target=work) #耗时 2.0415523052215576s多
l.append(p)
p.start()
for p in l:
p.join()############加这个join 的作用是为了统计总共的运行时间,主进程或者主线程要等待
# 子进程(线程)全部运行完,这才可以统计到全部的运行时间
stop = time.time()
print('run time is %s' % (stop - start))

###注意,这里的进程线程不能开得太多了,开得太多了会出问题,内存不够啊之类的错误



"""
无论是多进程还是多线程 你都不应该无限制开下去
因为这样会造成硬件层面上的损坏 一旦硬件损坏了 你的代码再牛逼也没有用武之地

原因
为了保证计算机硬件能够正常运行

池:
降低了程序的运行效率但是保证了计算机硬件安全
进程池和线程池就是用来限制同时处理的进程和线程的数量
"""

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

# pool = ThreadPoolExecutor(20) # 不传参数默认是你当前计算机CPU个数的五倍
# 会创建一个池子 里面固定已经产生了20个线程
# 后面的时候,我们就不需要再创建线程或者进程了,直接往这个池子里提交任务就可以了
# 创建线程池,永远固定的是这几个线程在这在个池子里,不是动态创建动态销毁,而是一直都在这里是一样的


pool = ThreadPoolExecutor(10)


def task(n):
print(n, os.getpid())
time.sleep(3)


if __name__ == '__main__':
for i in range(20):
pool.submit(task, i) #这就是往线程池中提交任务
#这里是有问题的 在创建线程池的时候,就已经创建好了那么多个线程,例如是10个,上面写的是10个
#但是,我们只需要将任务不断的提交给这个线程池就可以了
#但是这里的执行结果,每次都是同一个线程号,这就有问题了 还没找到原因

##回答上面的疑问:我们打印的os,getpid() 是进程号,而不是线程号,我们创建的那么多的线程,都是在这一个线程下面的
##所以我打印出来的PID号都是一样的,因为PID 指的是process ID ,进程ID
##如果打印线程号的话,那个就应该是10个线程号码循环出现

#下面这种做法就是创建了一个进程池,将
# pool = ProcessPoolExecutor(10)
#
#
# def task(n):
# print(n, os.getpid())
# time.sleep(3)
#
#
# if __name__ == '__main__':
# for i in range(20):
# pool.submit(task, i) #这就是往线程池中提交任务


from threading import Thread,Lock,RLock
import time

# mutexA=Lock()
# mutexB=Lock()
mutexB=mutexA=RLock() # 递归锁
"""
递归锁自身有计数功能 他能够记住 被acquire了多少次
只有第一个抢到递归锁才能够连续的acquire连续的release
"""

class Mythead(Thread):
def run(self):
self.f1()
self.f2()

def f1(self):
mutexA.acquire()
print('%s 抢到A锁' %self.name)
mutexB.acquire()
print('%s 抢到B锁' %self.name)
mutexB.release()
mutexA.release()

def f2(self):
mutexB.acquire()
print('%s 抢到了B锁' %self.name)
time.sleep(2)
mutexA.acquire()
print('%s 抢到了A锁' %self.name)
mutexA.release()
mutexB.release()

if __name__ == '__main__':
for i in range(100):
t = Mythead()
t.start()
 
原文地址:https://www.cnblogs.com/1832921tongjieducn/p/11312601.html