記事ディレクトリ
序文
マルチプロセス、マルチスレッド、非同期の例をいくつか共有し、メモを書いて記録します。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、マルチスレッド化
-
スレッドインポートスレッドからのマルチスレッドモジュール
-
マルチスレッドを実装するいくつかの方法:
スレッドによって実行される関数を作成し、この関数を Thread オブジェクトに渡して実行させる Thread
クラスを継承し、新しいクラスを作成し、実行するコードを run に書き込む関数 -
マルチスレッドの例
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
......
......
......