进程线程

一. 进程

   1. 同步异步概念

           

    异步:指 主进程和子进程同时执行  分配一个子进程就去执行一个 

    同步:指分配一个子进程时,必须等到这个子进程执行完才会继续分配写一个子进程任务然后执行....

   当p.start下面 写入 p.jion时  主程序会阻塞在这里让没有完成的子进程继续执行     主进程必须等待 子进程执行完才执行下一       步  p.daemon=True  设置 守护进程  子进程会随主进程结束而结束 ,设置在p.start()之前

 

    2.阻塞 例如  程序运行时遇到input , while True: 等等

   2.多进程  

       速度慢于pool.map 快于同步pool.apply

from multiprocessing import Process
import time
def func(num):
    time.sleep(0.5)
    print(num)
if __name__ == '__main__':
    l=[]
    start_time = time.time()
    for i in range(50):
        p = Process(target=func, args=(i,))
        p.start()
        l.append(p)
    [p.join() for p in l]
    print(time.time() - start_time)

    [p.join() for p in l]   将主进程阻塞   一次性最多执行的个数取决于cpu  一直在开进程   

   主进程等待所有子进程执行完,    而pool.apply是下一个要执行的进程等待上一个没有执行完的任务每一个都要等所以非常慢

   3.进程池 的几个方法

      最佳开启进程数  os.cpu_count()+1   一次性最多执行的个数

    1.pool.map

             参数:  函数,可迭代对象             速度慢于异步   

             pool.map 一次性执行进程池中的个数个进程    可以不添加pool.close  和pool.join 主进程也会等待子进程执行完才结束

            但执行顺序是混乱的  最好加上 

            返回值   ret=p.map ( func, [ ] )     为一个列表 值为func 的返回值 没有默认为None       

            运行时间0.900

from multiprocessing import Pool
import time
def func(num):
    time.sleep(0.5)
    print(num)
if __name__ == '__main__':
    start_time = time.time()
    p = Pool(5)
    p.map(func,[i for i in range(50)])
    print(time.time()-start_time)

           

    2. pool.apply

         一种默认同步的方法  速度最慢    进程池中的进程  都不是不是守护进程      每一个任务都要等待执行完

         参数:函数,args=( ) 元组 

         同步:我的池中即使有五个任务,也是一个任务一个任务的去执行上一个任务结束才执行下一个 

         原因:主进程会等待所有子进程执行完才继续往下执行         不用加  join 

         返回值: 就是执行函数的 返回值

from multiprocessing import Pool
import time
def func(num):
    time.sleep(0.5)
    print(num)
if __name__ == '__main__':
    start_time=time.time()
    pool = Pool(5)
    for i in range(50):
        pool.apply(func, args=(i,))

    print(time.time()-start_time)

      

   3.pool.apply_async

         一种异步的方法 ,速度极快  必须加pool.close()   pool.join  等待pool执行完   

         原因:进程池中的进程是守护进程,当主函数执行完时,而子程序没有执行完时时,子程序会被强制结束

         参数:函数,args=( ) 元组,callback=

        异步:我的池中有五个任务,就处理五个任务,接下来哪个任务处理完了,就马上去接受下一个任务

         返回值: 为一个对象  使用ret.get()  可以获得值,但是只能一个一个get 速度变慢

from multiprocessing import Pool
import time
def func(num):
    time.sleep(0.5)
    print(num)
if __name__ == '__main__':
    start_time = time.time()
    pool = Pool(5)
    for i in range(50):
        pool.apply_async(func, args=(i,))
    pool.close()
    pool.join()
    print(time.time() - start_time)

     二.pool.apply_async  之回调函数

      下图输出1-9,

        原因:  pool.apply_async中的第一个函数的return值 会默认返回到指定的callback函数中去当作形参接收  

from multiprocessing import Pool
import requests
url='https://www.baidu.com'
def func(url):
    r=requests.get(url)
    if r.status_code ==200:
        return url,r.text

def callback(item):
    url,page=item
    print(item)

if __name__ == '__main__':
    pool = Pool(5)
    for i in range(1):
        pool.apply_async(func, args=(url,),callback=callback)
    pool.close()
    pool.join()

   注意 :回调函数是由主进程调用的,而不是子进程,子进程只负责把返回结果给到回调函数

    所以回调函数执行的顺序是乱的 例如:

from multiprocessing import Pool
import requests
def func(url):
    print(url)
    r=requests.get(url)
    if r.status_code ==200:
        return url,r.text
def callback(item):
    url,page=item
    print(url)
if __name__ == '__main__':
    urls=[
        'https://www.dytt8.net/',
        'https://www.dy2018.com/html/gndy/',
        'http://desk.zol.com.cn/youxi/yingxionglianmeng/1920x1080/',
        'https://www.douyu.com/directory/myFollow'
    ]
    pool = Pool(5)
    for url in urls:
        pool.apply_async(func, args=(url,),callback=callback)
    pool.close()
    pool.join()

       输出结果为:

        https://www.dytt8.net/
         https://www.dy2018.com/html/gndy/
        http://desk.zol.com.cn/youxi/yingxionglianmeng/1920x1080/
        https://www.douyu.com/directory/myFollow
         http://desk.zol.com.cn/youxi/yingxionglianmeng/1920x1080/
        https://www.douyu.com/directory/myFollow
       https://www.dy2018.com/html/gndy/
       https://www.dytt8.net/

   4. 另一个模块的进程池  -异步--ProcessPoolExecutor

from concurrent.futures import ProcessPoolExecutor
import time

def fun(i):
    time.sleep(1)
    return i

if __name__ == '__main__':
    p = ProcessPoolExecutor(5)
    # for i in range(50):
    #     r=p.submit(fun,i)
    #     print(r.result())

    r = p.map(fun, [i for i in range(50)])
    p.shutdown()
    for i in r:
        print(i)
    print(r.__next__())

  这两种方式与下面的线程池类似

二.线程

   1.并发,并行

       并发:就是同时做多件事情。

       并行:就是把正在执行的大量任务分割成小块,分配给多个同时运行的线程。

       一般情况下,为了让CPU充分利用,并行处理都会采用多线程。

   2. 线程与进程比较

      开启很多进程时很慢,开启很多线程很快 

 

# 守护线程是根据主线程执行结束才结束
# 守护线程不是根据主线程的代码执行结束而结束
# 主线程会等待普通线程执行结束,再结束
# 守护线程会等待主线程结束,再结束
# 所以,一般把不重要的事情设置为守护线程
# 守护进程是根据主进程的代码执行完毕,守护进程就结束
def func():
    time.sleep(2)
    print(123)

def func1():
    time.sleep(5)
    print('abc')
if __name__ == '__main__':
    t = Thread(target=func)
    t.daemon = True
    t.start()
    t1 = Thread(target=func1)
    t1.start()
    print(99999999999999999999)

    以上输出:  先打印9999...在打印123,在打印abc

   原因:# 守护线程是根据主线程执行结束才结束 守护线程不是根据主线程的代码执行结束而结束

         当执行到9999时代码已经执行完,  此时如果是守护进程会随代码结束而结束,   而守护线程会随程序结束而结束 

        而func1不是守护线程  所以程序没有结束  所以先打印123,在打印abc

二.线程池 ---另一个模块--ThreadPoolExecutor

from concurrent.futures import ThreadPoolExecutor
from time import sleep
import time
def func(i):
    sleep(1)
    # print(i)
    return i

t=ThreadPoolExecutor(25)
for i in range(200):
    a=t.submit(func,i)
    print(a.result())
t.shutdown()

第二种和第一种一样,只是拿结果的时候不同        这里的map和进程池中的map返回结果不一样
start_time = time.time()
r=t.map(func,[i for i in range(50)])       这里是一个生成器对象,而进程池的map是一个列表
t.shutdown()
for i in r:                             用print(r.__next__()) 也可以一个一个拿
    print(i)
print(time.time()-start_time)

     在拿返回值的时候  第一种 就像同步一样,必须等到上一个拿到返回值才会去做下一个

     而第二个不会影响异步的效果

     也有一个回调函数

from concurrent.futures import ThreadPoolExecutor
from time import sleep
import time
def func(i):
    sleep(2)
    return i

def call(i):
    print(i.result())

t=ThreadPoolExecutor(25)
for i in range(200):
    a=t.submit(func,i).add_done_callback(call)

t.shutdown()

  

   五.总结

    一.在for 循环中  只要接收 了线程的返回值  就必须等待 拿到这个接受的值,下一个线程或进程才会继续,,而用map方法不会这样

      多进程中   from multi processing import Pool   

      1. pool.map  返回值是一个列表     没有回调 函数   需要加  close  join

      2.pool.apply  返回值就是 调用函数的返回值 没有回调 函数  不需要 close join 

      3.pool.apply_async   返回值是 一个对象  用 get() 获取   回调函数 callback=func()  接受被调用函数的返回值  一个元组

      线程池     需要close join

  多线程中  from threading import Thread

      1.普通多线程  取不到返回值  没有回调函数  需要  join

  二.两个异步的进程池线程池

     from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

 用submit(func,i) 提交任务    

  for i in range(200):     

        a=t.submit(func,i)                   这里接受了 返回值 所以变慢   返回值用   result() 获取

        print(a.result())

         t.shutdown()                     相当于  close(),join()

 两个都有map方法

r=t.map(func,[i for i in range(50)])
t.shutdown()
for i in r:                返回值是yield 那样的  生成器 generator 可以遍历
    print(i)              #print(r.__next__())  一个一个拿

  两个都有回调函数

for i in range(200):
    a=t.submit(func,i).add_done_callback(call)       

t.shutdown()

        

      

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值