【第58天】python全栈从入门到放弃

1 递归锁Rlock()和互斥锁

递归锁

代码块
from threading import  Thread,RLock,Lock
import  time

def func(r,i):
    r.acquire()  #三个acquire()不是并列,是内外嵌套,第一层,在同一个线程内,递归锁可以无止尽的acquire,但是互斥锁不行
    r.acquire()   #第一次里面的第二层

    r.acquire()   #第二层里面的最里层
    print(i)
    r.release()   #释放最里层
    r.release()   #释放中间
    r.release()    #释放最外层,三层全部释放了,才能开始下一个线程。
    #在不同的线程内,递归锁是保证只能被一个线程拿到钥匙,然后无止尽的acquire,其他线程等待,只有前面的release()全部的acquire()才能开始

r=RLock()   #开启一个递归锁

for i in range(10):
    Thread(target=func,args=(r,i,)).start()   #开启10个线程

互斥锁

代码块
from threading import Thread,Lock  #导入线程,递归锁
import time

def func(i,l):
    l.acquire()  #互斥锁只能有一个acquire()和一个release()
    time.sleep(0.5)
    print(i)
    l.release()

l = Lock()
for i in range(10):
    Thread(target=func,args=(i,l)).start()

2 条件Condition

代码块
条件 涉及 4个方法:
   con.acquire()
   con.release()
   con.wait()  # 假设有一个初始状态为False,阻塞。一旦接受到notify的信号后,变为True,不再阻塞
   con.notify(int)  给wait发信号,发int个信号,会传递给int个wait,让int个线程正常执行

条件的例子

代码块
from threading import Condition,Thread
import time

def func(con,i):
    con.acquire()# 主线程和10个子线程都在抢夺递归锁的一把钥匙。
    # 如果主线程抢到钥匙,主线程执行while 1,input,然后notify发信号,还钥匙。但是,此时如果主线程执行特别快
    # 极有可能接下来主线程又会拿到钥匙,那么此时哪怕其他10个子线程的wait接收到信号,但是因为没有拿到钥匙,所以其他子线程还是不会执行
    con.wait()
    print('第%s个线程执行了'%i)
    con.release()

con = Condition()
for i in range(10):
    t = Thread(target=func,args = (con,i))
    t.start()   #开启10个线程

while 1:
    # print(123)
    con.acquire()
    num = input('>>>')
    con.notify(int(num))
    con.release()
    time.sleep(0.5) # 为什么要加这个time.sleep(0.5)   主线程和10个子线程都在抢夺递归锁的一把钥匙。
    # 如果主线程抢到钥匙,主线程执行while 1,input,然后notify发信号,还钥匙。但是,此时如果主线程执行特别快
    # 极有可能接下来主线程又会拿到钥匙,那么此时哪怕其他10个子线程的wait接收到信号,但是因为没有拿到钥匙,所以其他子线程还是不会执行
    #所以没有这个time.sleep(0.5)  子线程是不会拿到钥匙的。

3 守护进程和守护线程与父进程代码

守护线程

守护线程不是随着父线程的代码执行结束而结束,守护线程是随着父线程的执行结束而结束

代码块
from threading import Thread
from multiprocessing import Process
import time

def func_daemon():
    time.sleep(3)
    print('这是守护线程')

def func():
    time.sleep(5)
    print('这是普通线程')

# 守护进程是随着父进程的代码执行结束而结束


if __name__ == '__main__':
    t = Thread(target=func_daemon,)
    t.daemon = True   #设置为守护
    t.start()

    t1 = Thread(target=func, )
    t1.start()
    print('这里是父线程')
    time.sleep(20)

守护进程是随着父进程的代码执行结束而结束

代码块
from threading import Thread
from multiprocessing import Process
import time

def func_daemon():
    # time.sleep(3)
    print('这是守护进程')

def func():
    time.sleep(2)
    print('这是普通进程')




if __name__ == '__main__':
    p = Process(target=func_daemon, )
    p.daemon = True
    p.start()

    p1 = Process(target=func, )
    p1.start()
    print('这是父进程')#如果这里没有时间延迟,根本不会执行守护进程,因为代码已经结束了,虽然主进程还在等待普通进程。

4 线程池

4-1多任务提交

代码块
from concurrent.futures import ThreadPoolExecutor
import time

def func(num):
    sum = 0
    for i in range(num):
        sum += i
    print(sum)

t = ThreadPoolExecutor(20)
start = time.time()
t.map(func,range(1000))# 提交多个任务给池中。  等效于 for + submit
t.shutdown()
print(time.time() - start)

4-2 回调函数

代码块
from concurrent.futures import ProcessPoolExecutor
# 不管是ProcessPoolExecutor的进程池  还是Pool的进程池,回调函数都是父进程调用的。
import os
import requests

def func(num):
    sum = 0
    for i in range(num):
        sum += i
    return sum   #返回一个sum,回调函数接收



def call_back_fun(res):
    print(res.result(),os.getpid())
    # print(os.getpid())

if __name__ == '__main__':
    print(os.getpid())   #父进程的进程号
    t = ProcessPoolExecutor(20)
    for i in range(1000):
        t.submit(func,i).add_done_callback(call_back_fun)   #指明是哪一个回调函数
    t.shutdown()

4-3 怎样拿到线程池的返回值

第一钟方法:

代码块
from concurrent.futures import ThreadPoolExecutor
import time

def func(num):
    sum = 0
    for i in range(num):
        sum += i
    return sum

t = ThreadPoolExecutor(20)

# 下列代码是用map的方式提交多个任务,对应 拿结果的方法是__next__()  返回的是一个生成器对象
res = t.map(func,range(1000))
t.shutdown()
print(res.__next__())
print(res.__next__())
print(res.__next__())
print(res.__next__())

第二种方法:

代码块
from concurrent.futures import ThreadPoolExecutor
import time

def func(num):
    sum = 0
    for i in range(num):
        sum += i
    return sum

t = ThreadPoolExecutor(20)

# 下列代码是用for + submit提交多个任务的方式,对应拿结果的方法是result
res_l = []
for i in range(1000):
    re = t.submit(func,i)
    res_l.append(re)
t.shutdown()
# print(i.result() for i in res_l)
[print(i.result()) for i in res_l]
# 在Pool进程池中拿结果,是用get方法。   在ThreadPoolExecutor里边拿结果是用result方法

5 进程池,多进程,多线程处理任务的效率快慢对比

5-1进程池

代码块
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from multiprocessing import Pool

#  concurrent.futures 这个模块是异步调用的机制
#  concurrent.futures 提交任务都是用submit
#  for + submit 多个任务的提交
#  shutdown 是等效于Pool中的close+join,是指不允许再继续向池中增加任务,然后让父进程(线程)等待池中所有进程执行完所有任务。

# from multiprocessing import Pool.apply / apply_async
import time

def func(num):
    sum = 0
    for i in range(num):
        for j in range(i):
            for x in range(j):
                sum += x
    print(sum)


if __name__ == '__main__':
    # pool的进程池的效率演示
    p = Pool(5)
    start = time.time()
    for i in range(100):
        p.apply_async(func,args=(i,))   #异步
    p.close()
    p.join()
    print('Pool进程池的效率时间是%s'%(time.time() - start))
    #0.47秒用时

5-2 多进程

代码块
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from multiprocessing import Pool

#  concurrent.futures 这个模块是异步调用的机制
#  concurrent.futures 提交任务都是用submit
#  for + submit 多个任务的提交
#  shutdown 是等效于Pool中的close+join,是指不允许再继续向池中增加任务,然后让父进程(线程)等待池中所有进程执行完所有任务。

# from multiprocessing import Pool.apply / apply_async
import time

def func(num):
    sum = 0
    for i in range(num):
        for j in range(i):
            for x in range(j):
                sum += x
    print(sum)


if __name__ == '__main__':

    # 多进程的效率演示
    tp = ProcessPoolExecutor(5)
    start = time.time()
    for i in range(100):
        tp.submit(func, i)
    tp.shutdown()  # 等效于 进程池中的 close + join
    print('进程池的消耗时间为%s' % (time.time() - start))
    #用时0.56秒

5-3 多线程

代码块
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from multiprocessing import Pool

#  concurrent.futures 这个模块是异步调用的机制
#  concurrent.futures 提交任务都是用submit
#  for + submit 多个任务的提交
#  shutdown 是等效于Pool中的close+join,是指不允许再继续向池中增加任务,然后让父进程(线程)等待池中所有进程执行完所有任务。

# from multiprocessing import Pool.apply / apply_async
import time

def func(num):
    sum = 0
    for i in range(num):
        for j in range(i):
            for x in range(j):
                sum += x
    print(sum)


if __name__ == '__main__':

    # 多线程的效率
    tp = ThreadPoolExecutor(20)
    start = time.time()
    for i in range(100):
        tp.submit(func,i)
    tp.shutdown()# 等效于 进程池中的 close + join
    print('线程池的消耗时间为%s'%(time.time() - start))
    #用时0.42

5-4结论

针对计算密集的程序来说
不管是Pool的进程池还是ProcessPoolExecutor()的进程池,执行效率差不多一样
ThreadPoolExecutor 的效率要差很多
所以 当计算密集时,使用多进程。
针对IO等阻塞的程序来说,使用线程切换的速度快,所以使用多线程。


别跑,点个赞再走
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,137评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,824评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,465评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,131评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,140评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,895评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,535评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,435评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,952评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,081评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,210评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,896评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,552评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,089评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,198评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,531评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,209评论 2 357

推荐阅读更多精彩内容