多进程、多线程与协程

  • 2019 年 10 月 10 日
  • 笔记

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/y_silence_/article/details/101605333

多进程、多线程与协程

目录

  • 代码整理
    • 进程池
    • 多线程
    • 线程池
    • 协程
  • 应用场景
    • 概述
    • 确定线程池大小
    • 确定进程池大小
    • 解决方案
  • 进一步理解
    • 前言
    • 多进程&多线程
      • 概述
      • 优劣
      • 区别
    • 线程池作用&原理
      • 线程池作用
      • 线程池原理
  • 参考内容
  • 总结

一、代码整理

1.1 进程池

from multiprocessing import Pool  import os, time, random    def long_time_task(name):      print('Run task %s (%s)...' % (name, os.getpid()))      start = time.time()      time.sleep(random.random() * 3)      end = time.time()      print('Task %s runs %0.2f seconds.' % (name, (end - start)))    if __name__=='__main__':      print('Parent process %s.' % os.getpid())      p = Pool(4)      for i in range(5):          p.apply_async(long_time_task, args=(i,))      print('Waiting for all subprocesses done...')      p.close()      p.join()      print('All subprocesses done.')

1.2 多线程

import time, threading    def loop():      print('thread %s is running...' % threading.current_thread().name)      n = 0      while n < 5:          n = n + 1          print('thread %s >>> %s' % (threading.current_thread().name, n))          time.sleep(1)      print('thread %s ended.' % threading.current_thread().name)    print('thread %s is running...' % threading.current_thread().name)  t = threading.Thread(target=loop, name='LoopThread')  t.start()  t.join()  print('thread %s ended.' % threading.current_thread().name)

1.3 线程池

from concurrent.futures import ThreadPoolExecutor  import urllib.request  import time    def fetch_url(url):      u = urllib.request.urlopen(url)      data = u.read()      print('data', data)      return data    pool = ThreadPoolExecutor(10)    start = time.time()  # Submit work to the pool  a = pool.submit(fetch_url, 'http://www.python.org')  b = pool.submit(fetch_url, 'http://www.pypy.org')    # Get the results back  x = a.result()  y = b.result()    end = time.time()  print('runtime %d' % (end - start))

1.4 协程

def consumer():      r = ''      while True:          n = yield r          if not n:              return          print('[CONSUMER] Consuming %s...' % n)          r = '200 OK'    def produce(c):      c.send(None)      n = 0      while n < 5:          n = n + 1          print('[PRODUCER] Producing %s...' % n)          r = c.send(n)          print('[PRODUCER] Consumer return: %s' % r)      c.close()    c = consumer()  produce(c)

二、应用场景

2.1 概述

多进程适合在 CPU 密集型操作(cpu 操作指令比较多,如位数多的浮点运算)。 多线程适合在 IO 密集型操作(读写数据操作较多的,比如爬虫)。 协程间是协同调度的,这使得并发量数万以上的时候,协程的性能是远远高于线程。

2.2 确定线程池大小

最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目

2.3 确定进程池大小

最佳线程数目 = CPU数目,即一个 CPU 执行一个进程。

2.4 解决方案

多进程 + 协程 既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。

三、进一步理解

3.1 前言

copy代码,很容易就可以参考着用,可是明白底层的原理是非常之关键的。

3.2 多进程&多线程

3.2.1 概述

进程是操作系统分配资源(比如内存)的最基本单元 线程是操作系统能够进行调度和分派的最基本单元。 多进程允许多个任务同时运行。 多线程允许将单个任务分成多个子任务运行。

3.2.2 优劣

多进程优点:稳定性高,因为一个子进程崩溃了,不会影响主进程和其他子进程。 多线程缺点:任何一个线程挂掉都可能直接造成整个进程崩溃,因为所有线程共享进程的内存。

3.2.3 区别

多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响。 多线程中,所有变量都由所有线程共享。

3.3 线程池作用&原理

3.3.1 线程池作用

有效的降低频繁创建销毁线程所带来的额外开销。

3.3.2 线程池原理

采用预创建的技术,在应用启动之初便预先创建一定数目的线程。应用在运行的过程中,需要时可以从这些线程所组成的线程池里申请分配一个空闲的线程,来执行一定的任务,任务完成后,并不是将线程销毁,而是将它返还给线程池,由线程池自行管理。

四、参考内容

五、总结

代码谁都会写,但是底层懂才是真的懂。