• 并发编程


    并发编程

    并发:假的多任务

    并行:真的多任务

    多线程threading,利用cpu和i/o 可以同时执行的原理,让CPU不在等待i/o完成

    多进程multiprocessing,利用多核CPU的能力,真正的平行执行任务

    异步i/o asyncio ,在单线程利用CPU和io同时执行的原理,实现函数异步执行

    使用lock对资源加锁,防止冲突访问

    使用queue实现不同线程、进程之间的数据通信,实现生产者和消费者模型

    使用线程池Pool,进程池Pool。简化线程进程的任务提交,等待结果,获取结果。

    使用subprocess启动外部程序的进程,并进行输入输出交互。

    CPU密集型:

      是i/o在很短的时间内可以完成,CPU需要大量的计算和处理,特点是CPU的利用率相当的高

      压缩和解压缩,加密解密,正则表达式等

    i/o密集型:

      是系统运作大部分的状况是CPU在等i/o的读写操作,CPU的利用率低

      文件处理程序,网络爬虫程序,读写数据库程序

    多线程Thread

    优点:相比进程,更加轻量级,占用资源少

    缺点:相对进程,多线程只能并发执行,不能利用多cpu(GIL)

       相比协程,启动数目有限,占用资源,有线程切换开销

    适用于:i/o密集型计算,同时运行的任务数目要求不多

    多线程数据通信的queue.Queue

    queue.Queue可以用于多线程之间的,线程安全的数据通信

    1. 引入类库

    import  queue

    2,创建Queue

    q = queue.Queue()

    3.添加元素

    q.put(item)

    4.获取元素

    item = q.get()

    5.查询状态

      q.qsize()  #用来判断元素的多少

      q.empty()  #用来判断是否为空

      q.full()  # 判断是否已满 

    lock 用于解决线程安全问题

    用法一:try——finally模式

    import threading

    lock = threading.Lock()

    lock.acquire()

    try:

      #do something

    finally:  

      lock.release()

    用法二:with模式

    import threading

    lock = threading.Lock()

    with lock:

      #do something

    线程池

    优点:

    1. 提升性能:因为减去了大量新建,终止线程的开销,重用了线程的资源:

    2. 适用场景:事和处理突发性大量请求或者需要大量线程完成任务,但实际任务处理时间较短

    3. 防御功能:有效避免系统因为创建线程过多,而导致的负荷过大相应变慢的问题

    4. 代码优势:使用线程池的语法比自己兴建线程执行更加简洁

    线程的生命周期

    ThreadPoolExecutor的使用语法

    方式一:map函数,很简单

    注意:map的结果和入参是顺序对应的

    from  concurrent.future import ThreadPoolExecutor,as_completad

    with ThreadPoolExecutor() as pool:

      results = pool.map(craw,urls)  #urls 为参数列表

      for  result in results:

        print(result)

    方式二:future模式,更强大

    注意:如果使用as_completed顺序是不定的

    from  concurrent.future import ThreadPoolExecutor,as_completad

    with ThreadPoolExecutor() as pool:

      futures = [pool。submit(crawl,url  for url in urls]

      for future in futures:  # 有序返回

        print(future.result())  

      for future in as_completed(futures): # 无序返回

        print(future.result())

    使用线程池改造程序

    多进程process

    优点:可以利用多核CPU并行运算

    缺点:占用资源最多,可启用的数目比线程少

    适用于:CPU密集型计算

    注意点:

    多协程Corutine

    优点:内存开销最少,启动的线程数目多

    缺点:支持的库有限(aiohttp vs requests)代码实现复杂

    适用于:i/o密集型计算,需要超多任务运行,但有现成库支持的场景

    GIL(全局解释器锁)

      是计算机编程语言解释器用于同步线程的一种机制,它使得任何时可仅有一个行程在执行,即使在多核心处理器上,使用GIL的解释器也只允许同一时间执行一个线程。(保证引用计数器的安全)

     Python  异步i/o库介绍:asyncio

    注意:

    要用在异步i/o编程中

    依赖的库必须支持异步i/o特性

    爬虫引用中:

    requests  不支持异步,需要用aiohttp

    import asyncio

    #获取事件循环

    loop =  asyncio.get_event_lppp()

    #定义协程

    saync def myfunc():

      await get_url(url)

    # 创建task列表

    tasks = [loop.create_task(myfunc(url) for  url  in  urls]

    # 执行爬虫事件列表

    loop.run_until_complete(asyncio.wait(tasks))

     信号量(英语:Semaphore)

    信号量,又称为信号量。旗语是一个同步对象,用于保持在0到指定最大值之间的一个数值

     1. 当线程完成一次对该semaphore对象的等待(wait)时,该计数值减一。

     2. 当线程完成一次对semaphore对象的释放(release)时,计数值加一。

     3. 当计数值为0 ,测线程等待该semaphore对象不再能成功直到该semaphore对象变成signaled状态

     4. semaphore对象的计数值大于0 ,为signaled状态,计数值等于0,为nonsignaled状态。

    使用方法一:

    sem = asynciko。Semaphore(10)

    @  ...later

    async with sem:

    # work with shared  resource

    使用方法二

    sem = asyncio.Semaphore(10)

    #  ....later

    await  sam.acquire()

    try:

      # work with shared resource

    finally:

      sem.release()

     使用subprocess启动电脑的子进程

     subptoces 模块:

    允许你生成新的进程

    连接它们的输入,输出,错误管道

    并且获取它们的返回值

     应用场景

    每天定时8:00自动打开酷狗音乐播放歌曲

    调用7z。exe自动解压缩.7z文件

    通过Python远程提交一个torrent种子文件,用电脑启动下载

    好好学习,天天向上。
  • 相关阅读:
    为什么Go没有三元运算符
    [Win10]鼠标没用,插入USB口电脑提示USB Optical Mouse找不到驱动程序的解决方案
    Office2016软件安装教程
    office2019软件安装教程
    Go语言 科学计算库 Gonum 学习1
    AI Studio 学习 Go 豆瓣电影爬取
    Git下载、安装与环境配置
    VueJS 数组哪些方法是响应式的
    VueJS v-for
    VueJS v-show
  • 原文地址:https://www.cnblogs.com/liuun/p/14975008.html
Copyright © 2020-2023  润新知