2016-08-11 8 views
8

मॉडलिंग करके अभिनेता मॉडल को समझना मैं समझ रहा हूं कि 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) 

इस समझ सही है? भले ही बैंक निकासी के दौरान सोता है, फिर भी कोई वापसी वापसी डेटा को दूषित नहीं कर सकती है क्योंकि इसे निकासी के मुकाबले एक अलग धागे पर प्रबंधित किया जाता है।

उत्तर

2

एक साथ वापसी नहीं रह गया हो सकता है, सच है, लेकिन क्योंकि withdraw संदेशों क्रमानुसार नियंत्रित किया जाता है, समवर्ती नहीं, Bank.read_messages पाश अंदर ही Bank धागा द्वारा यह है। इसका मतलब है कि sleep आदेशों को भी क्रमशः निष्पादित किया जाता है; पूरी संदेश कतार रुकने जा रही है और जब भी बैंक को वापसी के दौरान सोना पड़ता है तो 2 सेकेंड के लिए नियंत्रण उत्पन्न होता है। (Bank की मॉडलिंग कार्रवाई को देखते हुए, यह अनिवार्य रूप से अपरिहार्य है)।

2

यदि किसी ऑब्जेक्ट तक पहुंच को एक थ्रेड से अलग किया जाता है तो इसे आम तौर पर थ्रेड सुरक्षित माना जाता है।

अन्य अभिनेता सीधे बैंक के भंडारण तक नहीं पहुंच सकते हैं, लेकिन केवल वापसी के अनुरोध के संदेश भेजते हैं, इसलिए केवल बैंक थ्रेड में अपडेट होते हैं और मूल डिज़ाइन में चेक-एंड-सेट रेस हालत समाप्त हो जाती है।

+0

पाइथन थ्रेड वैश्विक नामस्थान साझा करते हैं, हालांकि, यह सुनिश्चित करने के लिए कि अलगाव वास्तव में वस्तु को थ्रेड-सबूत करता है, आपको ऑब्जेक्ट को फ़ंक्शन में स्थानीय बनाना होगा। एक अभिनेता मॉडल में, आमतौर पर इसका मतलब है कि आप जिस वैश्विक वस्तु को वैश्विक रूप से उजागर करना चाहते हैं वह किसी प्रकार का संदेश प्रेषक है, फिर प्रत्येक अभिनेता थ्रेड में * किसी अन्य फ़ंक्शन के अंदर * चलाया जाता है और चलाता है, और वहां से संदेशों के लिए प्रेषक के साथ जांच करता है। –

संबंधित मुद्दे