Python之線程代替方案 - 多進程

線程代替方案

  • subprocess 
    • 完全跳過線程,使用進程
    • 是派生進行的主要替代方案
    • python2.4後進入
  • multiprocessiong 
    • 使用thronging接口派生,使用子進程
    • 允許爲多核或者多cpu派生進程,接口跟threading非常相似
    • python2.6
  • concurrent.futures 
    • 新的異步執行模塊
    • 任務級別的操作
    • python3.2後引入

多進程

  • 進程間通訊(InterprocessCommunication,IPC)
  • 進程之間無任何共享狀態
  • 進程的創建 
    • 直接生成Process實例對象。
    • 派生子類。
# 直接生成Process實例對象
# -*- coding:utf-8 -*-

import multiprocessing
from time import sleep, ctime


def clock(interval):
    i = 0
    while i < 5:
        print("The time is %s" % ctime())
        sleep(interval)
        i += 1


if __name__ == '__main__':
    p = multiprocessing.Process(target=clock, args=(5,))
    p.start()
The time is Mon Jul  2 14:07:34 2018
The time is Mon Jul  2 14:07:39 2018
The time is Mon Jul  2 14:07:44 2018
The time is Mon Jul  2 14:07:49 2018
The time is Mon Jul  2 14:07:54 2018
# 派生子類
# -*- coding:utf-8 -*-

import multiprocessing
from time import sleep, ctime


class ClockProcess(multiprocessing.Process):
    """
        兩個函數比較
        1、init構造函數
        2、run
    """

    def __init__(self, interval):
        super().__init__()
        self.interval = interval

    def run(self):
        i = 0
        while i < 5:
            print("The time is %s" % ctime())
            sleep(self.interval)
            i += 1


if __name__ == "__main__":
    p = ClockProcess(3)
    p.start()
The time is Mon Jul  2 14:08:09 2018
The time is Mon Jul  2 14:08:12 2018
The time is Mon Jul  2 14:08:15 2018
The time is Mon Jul  2 14:08:18 2018
The time is Mon Jul  2 14:08:21 2018
  • 在os中查看pid,ppid的關係
# -*- coding:utf-8 -*-
from multiprocessing import Process
import os


def info(title):
    print(title)
    print("module name:", __name__)
    # 得到父進程的ID
    print("parent process:", os.getppid())
    # 得到本身進程的ID
    print("process id :", os.getpid())


def f(name):
    info('function f')
    print('hello', name)


if __name__ == '__main__':
    info('main line')
    p = Process(target=f, args=('whj',))
    p.start()

 

main line
module name: __main__
parent process: 19586
process id : 20428
function f
module name: __main__
parent process: 20428
process id : 20463
hello whj

生產者消費者模型 

  • JoinableQueue
#生產者、消費者多進程的實現
#JoinableQueue好處:可以帶通知,可以等子進程都完成
import multiprocessing
from time import sleep, ctime


def consumer(input_q):
    print("Into consumer:", ctime())
    i = 0
    while i < 100:
        # 預處理項
        item = input_q.get()
        print("pull", item, "out of q")  # 此項替換爲有用的工作
        input_q.task_done()  # 發出信號通知任務完成
        i += 1
        print("Out of consumer:", ctime())


def producer(sequence, output_q):
    print("Into producer:", ctime())
    for item in sequence:
        output_q.put(item)
        print("put", item, "into q")
    print("Out of producer:", ctime())


if __name__ == "__main__":
    q = multiprocessing.JoinableQueue()
    # 運行消費者進行
    qc = multiprocessing.Process(target=consumer, args=(q,))
    qc.daemon = True
    qc.start()

    # 生產多個項,sequence代表要發給消費者的序列項
    # 在實踐中,這可能是生成器的輸出或通過一些其他方法的返回
    sequence = [1, 2, 3, 4]
    producer(sequence, q)
    # 等待所有項被處理
    #要等待,如果不等待,那麼主進程完了,還有東西沒有消費完
    q.join()
  • 對列中哨兵的使用:通知作用 
# -*- coding:utf-8 -*-
import multiprocessing
from time import sleep, ctime


def consumer(input_q):
    print("Into consumer:", ctime())
    while True:
        # 預處理項
        item = input_q.get()
        if item is None:
            break
        print("pull", item, "out of q")  # 此項替換爲有用的工作
        input_q.task_done()  # 發出信號通知任務完成
        print("Out of consumer:", ctime())


def producer(sequence, output_q):
    print("Into producer:", ctime())
    for item in sequence:
        output_q.put(item)
        print("put", item, "into q")
    print("Out of producer:", ctime())


if __name__ == "__main__":
    q = multiprocessing.JoinableQueue()
    # 運行消費者進行
    qc = multiprocessing.Process(target=consumer, args=(q,))
    qc.daemon = True
    qc.start()

    # 生產多個項,sequence代表要發給消費者的序列項
    # 在實踐中,這可能是生成器的輸出或通過一些其他方法的返回
    sequence = [1, 2, 3, 4, -1]
    producer(sequence, q)
    q.put(None)  # 哨兵值
    # 等待所有項被處理
    qc.join()
  • 哨兵的改進,假設有多個消費者,通知多個消費者讓他們停止,就是多加了個none值 

 

#哨兵的改進,假設有多個消費者,通知多個消費者讓他們停止,就是多加了個none值
import multiprocessing
from time import sleep, ctime


def consumer(input_q):
    print("Into consumer:", ctime())
    while True:
        # 預處理項
        item = input_q.get()
        if item is None:
            break
        print("pull", item, "out of q")  # 此項替換爲有用的工作
        input_q.task_done()  # 發出信號通知任務完成
        print("Out of consumer:", ctime())


def producer(sequence, output_q):
    print("Into producer:", ctime())
    for item in sequence:
        output_q.put(item)
        print("put", item, "into q")
    print("Out of producer:", ctime())


if __name__ == "__main__":
    #Queue和JoinableQueue差不多
    q = multiprocessing.Queue()
    # 運行消費者進行
    qc1 = multiprocessing.Process(target=consumer, args=(q,))
    qc1.daemon = True
    qc1.start()

    qc2 = multiprocessing.Process(target=consumer, args=(q,))
    qc2.daemon = True
    qc2.start()

    # 生產多個項,sequence代表要發給消費者的序列項
    # 在實踐中,這可能是生成器的輸出或通過一些其他方法的返回
    sequence = [1, 2, 3, 4, -1]
    producer(sequence, q)
    q.put(None)  # 哨兵值
    q.put(None)
    # 等待所有項被處理
    qc1.join()
    qc2.join()

 

 

 

發佈了36 篇原創文章 · 獲贊 24 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章