多进程、多线程与协程
目录
- 代码整理
- 进程池
- 多线程
- 线程池
- 协程
- 应用场景
- 概述
- 确定线程池大小
- 确定进程池大小
- 解决方案
- 进一步理解
- 前言
- 多进程&多线程
- 概述
- 优劣
- 区别
- 线程池作用&原理
- 线程池作用
- 线程池原理
- 参考内容
- 总结
一、代码整理
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 线程池原理
采用预创建的技术,在应用启动之初便预先创建一定数目的线程。应用在运行的过程中,需要时可以从这些线程所组成的线程池里申请分配一个空闲的线程,来执行一定的任务,任务完成后,并不是将线程销毁,而是将它返还给线程池,由线程池自行管理。
四、参考内容
五、总结
代码谁都会写,但是底层懂才是真的懂。