Python マルチプロセス、マルチスレッド、非同期インスタンス


序文

マルチプロセス、マルチスレッド、非同期の例をいくつか共有し、メモを書いて記録します。

1. マルチプロセス

1. プロセス間通信はQueueキューを使用

キュー機能: 先入れ先出し、後入れ後出し

キューの使用: マルチプロセッシング モジュールのキューを使用して、複数のプロセス間でデータを転送できます。キュー自体はメッセージ キュー プログラムです。

Queue.qsize() : 現在のキューに含まれるメッセージ データを返します。

Queue.empty() : キューが空の場合は True を返し、それ以外の場合は False を返します。

Queue.full() : キューがいっぱいの場合は True を返し、それ以外の場合は False を返します。

Queue.get([block[,timeout]]) : キュー内のメッセージを取得し、キューから削除します。ブロックのデフォルトは True です。

Queue.put([item,[block[,timeout]]]) : 項目メッセージをキューに書き込みます。ブロックはデフォルトで True です。

from multiprocessing import Queue
q=Queue(2)
q.qsize()  #0
q.put('a')
q.put('b')
#q.put('c')  放不下了,因为队列中只能是2个  【阻塞】
q.get()  #a
q.get()  #b
#q.get()   取不了,因为队列中只能是2个   【阻塞】

2. マルチプロセスでの通信 [1 つは Queue に書き込み、1 つは Queue から読み取り]

from multiprocessing import Process,Queue
import os,time,random
def write(q): #写数据进程执行的代码
    for item in ['A','B','C']:
        print('Put {} to queue...'.format(item))
        q.put(item)
        time.sleep(random.randint(1,10))
def read(q):  #读数据进程执行的代码
    while True:
        if not q.empty():
            item=q.get(True)
            print('Get {} from queue'.format(item))
            time.sleep(random.randint(1,10))
        else:
            break
if __name__ == '__main__':
    q=Queue() #父进程创建Queue,并传给各个子进程
    pw=Process(target=write,args=(q,))
    pr=Process(target=read,args=(q,))
    pw.start() #启动子进程pw,写入
    pw.join()  #等待pw结束
    pr.start()  #启动子进程pr,读出
    pr.join()

3. プロセスプール内の通信 [上記のQueue()をManager().Queue()に変換するだけ]

from multiprocessing import Manager,Pool
import os
def reader(q):
    print('reader启动{},父进程为{}'.format(os.getpid(),os.getppid()))
    for i in range(q.qsize()):
        print('reader从Queue获取到消息:{}'.format(q.get(True)))

def writer(q):
    print('writer启动{},父进程为{}'.format(os.getpid(),os.getppid()))
    for i in 'PSY':
        q.put(i)
if __name__ == '__main__':
    print('{} start'.format(os.getpid()))
    q=Manager().Queue()  #使用Mananger中的Queue来初始化
    po=Pool()
    po.apply(writer,(q,))
    po.apply(reader,(q,))
    po.close()
    po.join()
    print('{} End'.format(os.getpid()))

結果は次のことを示しています。

15636 start
writer启动13592,父进程为15636
reader启动16656,父进程为15636
reader从Queue获取到消息:P
reader从Queue获取到消息:S
reader从Queue获取到消息:Y
15636 End

4. マルチプロセスコピーファイル[複数ファイルのコピー]

from multiprocessing import Pool,Manager
import os

def copyFileTask(name,oldFolderName,newFolderName,queue):  #完成copy一个文件的功能
    fr=open(oldFolderName+'/'+name,'r')
    fw=open(newFolderName+'/'+name,'w')
    content=fr.read()
    fw.write(content)
    fr.close()
    fw.close()
    queue.put(name)

def main():
    #0、获取要copy的文件夹的名字
    oldFolderName=input('请输入文件夹的名字:').strip()


    #1、创建一个文件夹
    newFolderName=oldFolderName+'-复件'
    os.mkdir(newFolderName)

    #2、获取old文件夹中的所有的文件名字
    fileNames=os.listdir(oldFolderName)  #fileNames是一个列表
    allNum=len(fileNames)

    #3、使用多进程的方法,copy原文件夹中的所有文件到新的文件夹中
    pool=Pool(5)
    queue=Manager().Queue()
    for name in fileNames:
        pool.apply_async(copyFileTask,args=(name,oldFolderName,newFolderName,queue))

    num=0
    while num<allNum:
        queue.get()  #这边的queue就是用来测试copy是否全复制完
        num+=1
        copyRate=num/allNum
        print('copy的进度为{:.2f}%'.format(copyRate*100))

    pool.close()
    pool.join()

if __name__ == '__main__':
    main()

2、マルチスレッド化

  1. スレッドインポートスレッドからのマルチスレッドモジュール

  2. マルチスレッドを実装するいくつかの方法:
    スレッドによって実行される関数を作成し、この関数を Thread オブジェクトに渡して実行させる Thread
    クラスを継承し、新しいクラスを作成し、実行するコードを run に書き込む関数

  3. マルチスレッドの例

1. ミューテックスを追加する

from threading import Thread,Lock
import time
class mythread(Thread):
    def __init__(self,threadname):
        Thread.__init__(self,name=threadname)
    def run(self):
        global x
        mutex.acquire()  #上锁
        for i in range(3):
            x = x+1
        time.sleep(1)
        print(x)  #运行程序,屏幕依次显示:3 6 9 12 15
        mutex.release()  #释放锁

if __name__ == '__main__':
    mutex=Lock()  #创建一把互斥锁,这个锁默认是没有上锁的
    t1 = []
    for i in range(5):
        t = mythread(str(i))
        t1.append(t)
    x = 0
    for i in t1:
        i.start()

結果は次のことを示しています。

3
6
9
12
15

2. ミューテックスに参加しない

from threading import Thread,Lock
import time
class mythread(Thread):
    def __init__(self,threadname):
        Thread.__init__(self,name=threadname)
    def run(self):
        global x
        #mutex.acquire()
        for i in range(3):
            x = x+1
        time.sleep(1)
        print(x)  #运行程序,屏幕依次显示:3 6 9 12 15
        #mutex.release()  #释放锁

if __name__ == '__main__':
    #mutex=Lock()  #创建一把互斥锁,这个锁默认是没有上锁的
    t1 = []
    for i in range(5):
        t = mythread(str(i))
        t1.append(t)
    x = 0
    for i in t1:
        i.start()

結果は次のことを示しています。

15
15
15
15
15

3. 画面上に ABC を 10 回連続して印刷します。

画面上にABCを10回連続で印刷します。

from threading import Thread,Lock
import time,random
mutex=Lock()
def print1(lock):
    lock.acquire()
    print('A')
    #time.sleep(random.randint(1,10))
    lock.release()
def print2(lock):
    lock.acquire()
    print('B')
    #time.sleep(random.randint(1,10))
    lock.release()
def print3(lock):
    lock.acquire()
    print('C')
    #time.sleep(random.randint(1,10))
    lock.release()
for i in range(10):
    t1=Thread(target=print1,args=(mutex,))
    t1.start()
    t1.join()
    t2 = Thread(target=print2, args=(mutex,))
    t2.start()
    t2.join()
    t3 = Thread(target=print3, args=(mutex,))
    t3.start()
    t3.join()

4. デッドロックの発生

from threading import Thread,Lock
import time
mutexA=Lock()
mutexB=Lock()
class MyThread1(Thread):
    def run(self):
        if mutexA.acquire():
            print(self.name+'---do1---up---')
            time.sleep(1)
            if mutexB.acquire():
                print(self.name+'---do1---down---')
                mutexB.release()
            mutexA.release()
class MyThread2(Thread):
    def run(self):
        if mutexB.acquire():
            print(self.name+'---do1---up---')
            time.sleep(1)
            if mutexA.acquire():
                print(self.name+'---do1---down---')
                mutexA.release()
            mutexB.release()
if __name__ == '__main__':
    t1=MyThread1()
    t2=MyThread2()
    t1.start()
    t2.start()

結果: [デッドロックが発生しました]

Thread-1---do1---up---
Thread-2---do1---up---

注: 例 4 の if name == ' main ':の関数セグメントを次のコードに変更すると、デッドロックは発生しません。

if __name__ == '__main__':
    t1=MyThread1()
    t2=MyThread2()
    t1.start()
    t1.join()
    t2.start()
    t2.join()

結果:

Thread-1---do1---up---
Thread-1---do1---down---
Thread-2---do1---up---
Thread-2---do1---down---

5. デッドロックへの対処

···程序设计时自己避免
mutex=Lock()
mutex.acquire([blocking])  #锁定
mutex.release()  #释放
其中acquire可以有一个blocking参数,如果设定blocking为True,则当前线程会阻塞,知道获取到这个锁为止,若没有指定,则默认为True
                                 如果设定blocking为False,则当前线程不会堵塞
···自己设置超时时间,若是到达该时间,就释放该锁

6. プロデューサー/コンシューマー モデル [一般的に使用される] —> クローラーなど: データのクローリング + データの処理 —> バッファリングにキューを使用

from queue import Queue  #队列,先进先出  【用于解耦合】
from threading import Thread
import time
class Producer(Thread):
    def run(self):
        global queue
        count=0
        while True:
            if queue.qsize()<1000:
                for i in range(100):  #只要当前队列中商品的数量小于1000,生产者开始生产产品(在主程序中定义了2个生产者)
                    count+=1
                    msg='生产产品{}'.format(count)
                    queue.put(msg)
                    print(msg)
            time.sleep(0.5)

class Consumer(Thread):
    def run(self):
        global queue
        while True:
            if queue.qsize()>100:
                for i in range(3):  #只要当前队列中商品的数量大于100,消费者开始消费产品(在主程序中定义了5个消费者)
                    msg = self.name+'消费了'+queue.get()
                    print(msg)
            time.sleep(1)
if __name__ == '__main__':
    queue=Queue()
    for i in range(50):
        queue.put('初始化商品:{}'.format(i))
    for i in range(2):  #创建2个生产者
        p=Producer()
        p.start()
    for i in range(5):  #创建5个消费者
        c=Consumer()
        c.start()

2、非同期

1.コンセプト

同期通話: たとえば、友人に夕食に電話し、友人が忙しい場合、あなたはずっとそこで待っていて、友人が終わったら一緒に食事に行きます。

非同期通話: たとえば、夕食のために友人に電話すると、友人は知っていると言い、忙しくなってからあなたのところに行くので、あなたは他のことができます。

2. 非同期呼び出しの小さな例:

from multiprocessing import Pool
import os,time

def test():
    print('--进程池中的进程--pid={}--ppid={}--'.format(os.getpid(),os.getppid()))
    for i in range(3):
        print('{}'.format(i))
        time.sleep(1)
    return 'hahaha'

def test2(args):
    print('--callback func--pid={}--'.format(os.getpid()))
    print('--callback func--args={}--'.format(args))

if __name__ == '__main__':
    pool=Pool(3)
    pool.apply_async(func=test,callback=test2)  #callback就是回调
    while True:
        time.sleep(1)
        print('----主进程--pid={}'.format(os.getpid()))

結果は次のことを示しています。

--进程池中的进程--pid=16412--ppid=5292--
0
----主进程--pid=5292
1
----主进程--pid=5292
2
----主进程--pid=5292
--callback func--pid=5292--
--callback func--args=hahaha--
----主进程--pid=5292
----主进程--pid=5292
----主进程--pid=5292
----主进程--pid=5292
......
......
......

おすすめ

転載: blog.csdn.net/Tom197/article/details/119888386