ディレクトリ
キュー、生産者 - 消費者モデルでは、最初のスレッドに会いました
まず、ロックを使用すると、投票アプレットをつかむために、プロセスを最適化します
1.1プロセス・ロック
プロセス間でデータを共有しますが、ファイルシステムの同じセットを共有するため、同じファイルへのアクセス、または端末で印刷しないでくださいことは問題ではありません。共有が競争によって引き起こされる、競争の結果は混乱をもたらすことです、それはロックプロセスを制御する必要があります。
同時で効率を犠牲にしても、シリアルになるが、競争を避けるために、並行して実行すると印刷複数のプロセスは、高効率、しかし、同じ印刷端末に対して競合する印刷障害をもたらし、その後も、同じ端末を共有します。
ロックは、データの同じ部分を確実にするために複数のプロセスを変更することができたときに、1つのタスクのみを修正することができると同時に、すなわち、シリアル変更され、速度が遅いが、データのセキュリティを確保します。
プロセス・ロックのニーズを使用してくださいfrom multiprocessing import Process ,Lock
1.2最適化のグラブ票アプレット
from multiprocessing import Process,Lock
import json,time,os
def search():
time.sleep(1) # 模拟网络io
with open('db.txt',mode='rt',encoding='utf-8') as fr:
res = json.load(fr)
print(f"还剩{res['count']}张票")
def get():
with open('db.txt',mode='rt',encoding='utf-8') as fr:
res = json.load(fr)
time.sleep(1)
if res['count'] > 0:
res['count'] -= 1
with open('db.txt',mode='wt',encoding='utf-8') as fw:
json.dump(res,fw)
print(f"进程{os.getpid()}抢票成功")
time.sleep(1.5) # 模拟网络io
else:
print('票已售罄!!!')
def task(lock):
search()
lock.acquire() # 用进程锁锁住
get()
lock.release() # 释放锁头
if __name__ == '__main__':
lock = Lock() # 写在主进程是为了让子进程拿到同一把锁
for i in range(15): # 同时有15个人抢票
p = Process(target=task,args=(lock,))
p.start()
# 进程锁和join用法的区别
# 进程锁:是把锁住的代码变成了串行
# join:是把所有的子进程变成了串行
# 为了保证数据的安全,只能串行,牺牲掉效率
第二に、キュー
はじめに2.1キュー
私たちはロックの問題を処理するのに役立つ1、高効率(複数のプロセスがメモリのデータを共有する)2、:プロセスのロック上記の例では、調整するためのソリューションを見つけることができます。
これは、メッセージベースIPC通信メカニズムのマルチプロセッシングモジュールは、私たちを提供しています:キューやパイプ
IPCメカニズム:プロセス・コミュニケーションズ
パイプライン:パイプベースの共有メモリ空間
キュー:キュー=パイプ+ロック
キューおよびパイプがメモリに保存されたデータであり、キューが(パイプライン+ロック)ロックの複雑な問題から、私たちは自由にさせ、達成するために基づいており、我々は、共有データを使用しないよう、できるだけ多くのメッセージングを使用するようにしてくださいそしてキューは、複雑な同期とロックの問題を扱う避けるため、だけでなく、プロセスの数が増加し、多くの場合、より優れた拡張性を得ることができます。
クラスキューを作成するために、2.2
これは、パイプの底部と達成するための手段にロックされています
Queue([maxsize]): 创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。maxsize是队列中允许最大项数,省略则无大小限制。
==その注意:キューは、通常の情報の一部を渡す転送大きなファイルには適していません==
で説明したクラスメソッド:**
主な方法:
1 q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。 2 q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常. 3 4 q.get_nowait():同q.get(False) 5 q.put_nowait():同q.put(False) 6 7 q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。 8 q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。 9 q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样
その他の方法(理解)
1 q.cancel_join_thread():不会在进程退出时自动连接后台线程。可以防止join_thread()方法阻塞 2 q.close():关闭队列,防止队列中加入更多数据。调用此方法,后台线程将继续写入那些已经入队列但尚未写入的数据,但将在此方法完成时马上关闭。如果q被垃圾收集,将调用此方法。关闭队列不会在队列使用者中产生任何类型的数据结束信号或异常。例如,如果某个使用者正在被阻塞在get()操作上,关闭生产者中的队列不会导致get()方法返回错误。 3 q.join_thread():连接队列的后台线程。此方法用于在调用q.close()方法之后,等待所有队列项被消耗。默认情况下,此方法由不是q的原始创建者的所有进程调用。调用q.cancel_join_thread方法可以禁止这种行为 '''
2.3ユースケースキュー
ケースワン
from multiprocessing import Process,Queue
q = Queue()
q.put('鸭屁屁') # 插入数据到队列中
q.put([1,2,4])
q.put(2)
print(q.get())
print(q.get())
print(q.get())
#q.put(5) # 往队列中再放入一个值,下面的代码就不会阻塞
print(q.get()) # 前三个已经把值拿掉了,这里就会默认一直等着拿值,就阻塞住了
ケースII
from multiprocessing import Process,Queue
q = Queue(4) # 括号里的参数是指定队列里值得最大个数
q.put('鸭屁屁')
q.put([1,2,3])
q.put([2,3,4])
q.put(5)
q.put(6) # 队列满了的情况再放值,会阻塞
ケースIII(以下、いくつかの例を理解するために)
from multiprocessing import Process,Queue
q = Queue(3)
q.put('zhao',block=True,timeout=2) # block=True:默认会阻塞,timeout:指定阻塞的时间
q.put('zhao',block=True,timeout=2)
q.put('zhao',block=True,timeout=2)
q.put('zhao',block=True,timeout=5) # put里的 block=True 如果满了会等待,timeout最多等待n秒,如果n秒队列还是满的就报错了
ケース四
from multiprocessing import Process,Queue
q = Queue()
q.put('yyyy')
q.get()
q.get(block=True,timeout=5) #get里的 block=True 阻塞等待,timeout最多等5s, 5s后还是取不到就报错
ケース5
from multiprocessing import Process,Queue
q = Queue(3)
q.put('qwe')
q.put('qwe')
q.put('qwe')
q.put('qwe',block=False) # 对于put来说 block=False 如果队列满了就直接报错
q = Queue(3)
q.put('qwe')
q.get()
q.get(block=False) # 对于get来说 block = Flase 拿不到不阻塞,直接报错
6例
from multiprocessing import Process,Queue
q = Queue(1)
q.put('123')
# q.get()
q.put_nowait('666') # put_nowait方法相当于put里的block = Flase
# q.get_nowait() # get_nowait方法相当于get里的block = Flase
第三に、生産者 - 消費者モデル
生産者 - 消費者モデルと3.1キューキューの実装
メーカー:生産データのタスク
消費者:処理データのタスク
プロデューサー - キュー(ポット) - >消費者
プロデューサーは、彼らの最大の生産性に到達するために、生産を停止することはできません、消費者が支出を保つことができ、また、彼らの最大の消費効率に達しました。
プロデューサーの消費者モデルが大幅に生産や個人消費効率の生産の効率を向上させることができます。
補足:キューは、大容量のファイル転送、メッセージの一部による生産のパスには適していません。
from multiprocessing import Process,Queue
import time,random
def producer(q,name,food):
'''生产者进程'''
for i in range(3):
print(f"{name}生产了{food}{i}")
time.sleep(random.randint(1,3))
res = f"{food}{i}"
q.put(res)
def consumer(q,name):
'''消费者进程'''
while True:
res = q.get(timeout=5)
if res is None:
break # 收到空信号就结束
time.sleep(random.randint(1,3))
print(f"{name}吃了{res}")
if __name__ == '__main__':
q = Queue()
# 生产者对象
p1 = Process(target=producer,args=(q,'rocky','生蚝'))
p2 = Process(target=producer,args=(q,'nick','韭菜'))
p3 = Process(target=producer,args=(q,'tank','扇贝'))
# 消费者对象
c1 = Process(target=consumer,args=(q,'蓬妹'))
c2 = Process(target=consumer,args=(q,'山鸡'))
# 生产者开始生产,消费者开始吃
p1.start()
p2.start()
p3.start()
c1.start()
c2.start()
# 必须保证生产者生产完才能发送结束的信号,用到Process的join方法
p1.join() # 感知子进程的结束
p2.join()
p3.join() # 到这里生产者生产完毕
q.put(None) # 有几个消费者就put几次
q.put(None)
キューJoinableQueue達成生産者 - 消費者モデルと3.2
JoinableQueue:これは、キューのオブジェクトのようだが、キューは、ユーザは、プロジェクトが正常に処理されたプロジェクトのプロデューサーを通知することができます。通知プロセスが達成するために共有信号と条件変数を使用しています。
同じ方法をさらに含むことに加えて、P JoinableQueueキュー・オブジェクトの例:
q.task_done():q.get()はアイテムが処理された返すことをユーザ信号この方法を使用します。このメソッドの呼び出しの数がキューから削除されたアイテムの数よりも大きい場合は、とValueErrorの例外がスローされます
q.join():キュー内のすべての項目が処理されるまでプロデューサーは、このメソッドのブロックを呼び出します。ブロッキングは、これまでq.task_done()メソッドを呼び出している各プロジェクトのためにキューイングしていきます。
from multiprocessing import Process,JoinableQueue
import time
import random
def producer(name,food,q):
'''生产者进程'''
for i in range(2):
time.sleep(random.randint(1,3))
res = f"{food}{i}"
q.put(res)
print(f'\033[44m{name} 生产了 {res}\033[0m')
q.join() #生产完毕,使用此方法进行阻塞,直到队列中所有项目均被处理。
def consumer(name,q):
'''消费者进程'''
while True:
res = q.get()
time.sleep(random.randint(1,3))
print(f"{name}吃了{res}")
q.task_done() #向q.join()发送一次信号,证明一个数据已经被取走了
if __name__ == '__main__':
q = JoinableQueue()
#生产者
p1 = Process(target=producer,args=('yjy','酱大骨',q))
p2 = Process(target=producer,args=('wwb','酸菜鱼',q))
p3 = Process(target=producer,args=('hhh','卤猪蹄',q))
#消费者
c1 = Process(target=consumer,args = ('xx',q,))
c2 = Process(target=consumer,args = ('yy',q,))
c1.daemon = True #将他设置为守护进程
c2.daemon = True #将他设置为守护进程
#开始生产,开始吃
l = [p1,p2,p3,c1,c2]
for i in l :
i.start()
#必须保证生产者生产完才能发送结束的信号,运用到.join
p1.join() #感知子进程的结束
p2.join()
p3.join()
print("主进程结束了")
'''
主进程等p1,p2,p3
P1,P2,p3等c,c2
p1,p2,p3结束了,证明c1,c2肯定全都收完了p1,p2,p3发到队列的数据
#因而c1,c2也没有存在的价值了,不需要继续阻塞在进程中影响主进程了。应该随着主进程的结束而结束,所以设置成守护进程就可以了。
'''