多進程、多線程與協程

多進程、多線程與協程

目錄

  • 代碼整理
    • 進程池
    • 多線程
    • 線程池
    • 協程
  • 應用場景
    • 概述
    • 確定線程池大小
    • 確定進程池大小
    • 解決方案
  • 進一步理解
    • 前言
    • 多進程&多線程
      • 概述
      • 優劣
      • 區別
    • 線程池作用&原理
      • 線程池作用
      • 線程池原理
  • 參考內容
  • 總結

一、代碼整理

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 線程池原理

採用預創建的技術,在應用啓動之初便預先創建一定數目的線程。應用在運行的過程中,需要時可以從這些線程所組成的線程池裏申請分配一個空閒的線程,來執行一定的任務,任務完成後,並不是將線程銷燬,而是將它返還給線程池,由線程池自行管理。

四、參考內容

五、總結

代碼誰都會寫,但是底層懂纔是真的懂。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章