मॉडलिंग करके अभिनेता मॉडल को समझना मैं समझ रहा हूं कि actor model बैंक को मॉडलिंग करके कैसे काम करता है।बैंक
import time
from threading import Thread
bank = {'joe': 100}
class Withdrawal(Thread):
"""
Models a concurrent withdrawal for 'joe'. In this example, 'bank'
is a shared resource not protected and accessible from any thread.
Args:
amount (double) how much to withdraw
sleep (bool) config to sleep the thread during the withdrawal
"""
def __init__(self, amount, sleep = False):
self.amount = amount
self.sleep = sleep
Thread.__init__(self)
def run(self):
"""
Overrides method in Thread.
Returns: void
"""
balance = bank['joe']
if balance >= self.amount:
if self.sleep:
time.sleep(5)
bank['joe'] -= self.amount
t1 = Withdrawal(80, True)
t2 = Withdrawal(80)
t1.start()
t2.start()
कोड चलाने के बाद, 'joe'
के लिए संतुलन -60
पांच के बाद सेकंड होना चाहिए: सबसे पहले, यहाँ कुछ illustrating कारण है कि हम समवर्ती प्रणालियों के लिए मॉडल की जरूरत है कोड है। ऐसा इसलिए है क्योंकि bank
समवर्ती पहुंच से असुरक्षित है, और समवर्ती निष्पादन के दौरान पांच सेकंड के लिए रुकने का अर्थ है कि हम गारंटी नहीं दे सकते कि विभिन्न राज्यों में डेटा तक नहीं पहुंचाया जाएगा। इस मामले में, पहला धागा दूसरे धागे को वापस लेने के बाद बैंक तक पहुंचता है लेकिन यह जांच नहीं करता कि वापसी अभी भी संभव है। नतीजतन खाता नकारात्मक हो जाता है।
यदि हम अभिनेताओं के रूप में बैंक और निकासी का मॉडल करते हैं, तो हम खाते तक पहुंच की रक्षा कर सकते हैं क्योंकि इसकी स्थिति एक अलग थ्रेड पर प्रबंधित होती है जो उससे निकालने की कोशिश करने वालों से अलग होती है।
from queue import Queue
from threading import Thread
import time
import random
class Actor(Thread):
"""
Models an actor in the actor model for concurrent computation
see https://en.wikipedia.org/wiki/Actor_model for theoretical overview
Args:
handles (dict) mapping of public methods that are callable
on message data after message has been read
"""
def __init__(self, handles):
self.handles = handles
self.mailbox = Queue()
Thread.__init__(self, daemon=True)
def run(self):
"""
Overrides method in Thread. Once the thread has started,
we listen for messages and process one by one when they are received
Returns: void
"""
self.read_messages()
def send(self, actor, message):
"""
Puts a Message in the recipient actor's mailbox
Args:
actor (Actor) to receive message
message (Message) object to send actor
Returns: void
"""
actor.mailbox.put(message)
def read_messages(self):
"""
Reads messages one at a time and calls the target class handler
Returns: void
"""
while 1:
message = self.mailbox.get()
action = message.target
if action in self.handles:
self.handles[action](message.data)
class Message:
"""
Models a message in the actor model
Args:
sender (Actor) instance that owns the message
data (dict) message data that can be consumed
target (string) function in the recipient Actor to we'd like run when read
"""
def __init__(self, sender, data, target):
self.sender = sender
self.data = data
self.target = target
class Bank(Actor):
"""
Models a bank. Can be used in concurrent computations.
Args:
bank (dict) name to amount mapping that models state of Bank
"""
def __init__(self, bank):
self.bank = bank
Actor.__init__(self, {'withdraw': lambda data: self.withdraw(data)})
def withdraw(self, data):
"""
Action handler for 'withdraw' messages. Withdraw
if we can cover the requested amount
Args:
data (dict) message data
Returns: void
"""
name, amount = data['name'], data['amount']
if self.bank[name] >= amount:
if data['sleep']:
time.sleep(2)
self.bank[name] -= amount
class Withdrawal(Actor):
"""
Models a withdrawal. Can be used in concurrent computations.
Args:
bank (Bank) shared resource to transact with
sleep (bool) config to request that the bank sleep during a withdrawal
"""
def __init__(self, bank, sleep=False):
self.bank = bank
self.sleep = sleep
Actor.__init__(self, {})
def withdraw(self, name, amount):
"""
Wrapper for sending a withdrawl message
Args:
name (string) owner of the account in our bank
amount (double) amount we'd like to withdraw
Returns: void
"""
data = {'sleep': self.sleep, 'name': name, 'amount': amount}
Actor.send(self, self.bank, Message(self, data, 'withdraw'))
चलो अब टेस्ट:
bank = Bank({'joe': 100})
bank.start()
actors = []
for _ in range(100):
a = Withdrawal(bank, random.randint(0, 1))
a.start()
actors.append(a)
for a in actors:
a.withdraw('joe', 15)
इस समझ सही है? भले ही बैंक निकासी के दौरान सोता है, फिर भी कोई वापसी वापसी डेटा को दूषित नहीं कर सकती है क्योंकि इसे निकासी के मुकाबले एक अलग धागे पर प्रबंधित किया जाता है।
पाइथन थ्रेड वैश्विक नामस्थान साझा करते हैं, हालांकि, यह सुनिश्चित करने के लिए कि अलगाव वास्तव में वस्तु को थ्रेड-सबूत करता है, आपको ऑब्जेक्ट को फ़ंक्शन में स्थानीय बनाना होगा। एक अभिनेता मॉडल में, आमतौर पर इसका मतलब है कि आप जिस वैश्विक वस्तु को वैश्विक रूप से उजागर करना चाहते हैं वह किसी प्रकार का संदेश प्रेषक है, फिर प्रत्येक अभिनेता थ्रेड में * किसी अन्य फ़ंक्शन के अंदर * चलाया जाता है और चलाता है, और वहां से संदेशों के लिए प्रेषक के साथ जांच करता है। –