An introduction to simplifying complex programming models with Python's simpy library _python

Source: Internet
Author: User
Tags in python

When I met one of SimPy's founder Klaus Miller, I learned about the bag from him. Dr. Miller has read several lovely Python columns that suggest techniques for using Python 2.2+ generators to implement semi-collaborative routines and "lightweight" threading. In particular (which I am pleased with), he found these techniques useful when implementing Simula-67 style simulations in Python.

The result is that Tony Vignaux and Chang Chui have previously created another Python library, which is conceptually closer to Simscript, and that the library uses standard threading techniques rather than my semi-collaborative routine technology. When the team studied together, it was thought that the model based on the builder was much more effective, and recently launched a GPL-using project on SourceForge, called SimPy (see Resources for a link to the SimPy homepage), which is currently in beta-beta status. Professor Vignaux hopes that he will use a unified SimPy package in the future University teaching at Victoria University in Wellington (University of Victoria), and I believe that the library is also well suited to apply to a variety of practical issues.

I acknowledge that I have no basic knowledge of simulation in the field of programming until recent communications and research. I guess most of the readers of this column, like me, know very little about this knowledge. While some might think that this style of programming is somewhat novel, impersonation is useful in understanding the behavior of real systems with limited resources. Whether you are interested in limited-bandwidth networks, car traffic behavior, market and commercial optimization, biological/evolutionary interactions, or other "random" systems, SimPy provides a simple Python tool for such modeling.
a random definition

Similar to "connection", it is one of the most appropriate words to describe its assignment-no more suitable:

Random (stochastic), derived from Greek stokhastikos (adjective)
1) speculative, relating to, or having a speculative character; good conjecture.
2 in Statistics: involves or contains a random variable or multiple random variables, or involves contingency or probability.

Source: dictionary.com

In this column, I'll always use a fairly simple example of a payment area with multiple channels in a grocery store. By using the simulations demonstrated, we can ask questions about the economic and latency implications of various changes to the scanner technology, shopper habits, staffing needs, and so on. The advantage of this modeling is that it allows you to make a strategy in advance when you have a clear idea of what your changes mean. It is clear that most readers do not specialize in a grocery store, but these technologies can be widely used in various systems.
The concept of simulation

The SimPy library provides only three abstract/parent classes, and they correspond to the three basic concepts of impersonation. There are many other general functions and constants that are used to control the operation of simulations, but important concepts are combined with these classes.

The core concept in the simulation is the process. A process is just an object that completes certain tasks, and then sometimes waits a moment before it is ready to complete the next task. In SimPy, you can also "deactivate" a process, which means that after a process completes a task, it does so only when other processes require the process to complete another task. It is often useful to treat a process as an attempt to accomplish a goal. When you write a process, you usually write it as a loop in which you can perform multiple operations. Between each operation, you can insert the Python "yield" statement, which lets the simulation scheduler execute each wait process before returning control.

Many of the actions that a process performs depend on the use of resources. Resources are limited only in terms of availability. In a biological model, resources may be food supplies; in the network model, the resource can be a router or a limited bandwidth channel; In our market simulation, the resource is the payment channel. The only task that a resource performs is to limit its use to a specific process at any given time. Under the SimPy programming model, the process alone determines how long it takes to retain resources, and the resource itself is passive. In a real-world system, the SIMPY model may or may not be suitable for conceptual scenarios, and it is easy to imagine that resources inherently limit their utilization (for example, if the server computer does not receive a satisfactory response within the required time frame, it interrupts the connection). However, as a programming issue, whether a process or resource is "active" is not particularly important (just make sure you understand your intent).

The last SimPy class is the monitoring program. In fact, the monitoring program is not very important, but it is very convenient. The whole task of the monitor is to record the events reported to it and to keep statistics about these events (averages, counts, variances, and so on). The Monitor class provided by this library is a useful tool for recording impersonation, but you can also log events through any other technology that you want to use. In fact, my example makes the Monitor subclass to provide some (slightly) enhanced capabilities.


Set up store: for analog programming

In most of the articles I've written, I'll give you a sample application right away, but in this case, I think every step that takes you through a grocery application is more useful. If you want, you can clip each part together; SimPy creators will include my example in a future release.

The first step in the SimPy simulation is a few general import statements:
Listing 1. Import SimPy Library

#!/usr/bin/env python from
__future__ import generators to
SimPy Import simulation from
simpy.simulation Import hold, request, release, now to
simpy.monitor import Monitor
import random from
math import sqrt

Some examples that come with SimPy use the import * style, but I prefer to make my populated namespaces clearer. For the Python 2.2 (the minimum version required for SimPy), you will need to import the generator attributes as noted. This is not necessary for a later version of Python 2.3.

For my application, I have defined several runtime constants that describe several scenarios I am interested in during a particular simulation run. When I change the scenario, I have to edit these constants within the main script. If the content of this application is more substantial, then I might configure these parameters with command-line options, environment variables, or configuration files. But for now, this style is enough:
Listing 2. Configuring Impersonation Parameters

aisles = 5     # Number of open aisles
itemtime = 0.1 # time to ring up one   item
avgitems =   # Average N  Umber of items purchased
CLOSING = 60*12  # Minutes from store open to store close
avgcust = 1500   # Average Number of daily customers
runs = # number of times to     run the simulation

The primary task that our simulations need to accomplish is to define one or more processes. For the analog grocery store, we are interested in the process of paying customers at the channel.
Listing 3. Define the actions of the customer

Class Customer (simulation.process):
  def __init__ (self):
    simulation.process.__init__ (self)
    # randomly Pick how many the items this customer is buying
    Self.items = 1 + int (random.expovariate (1.0/avgitems))
  def checkout (SE LF):
    start = Now ()      # Customer decides to check out
    yield request, self, checkout_aisle
    at_checkout = Now ()   # Customer gets to front of line
    waittime.tally (at_checkout-start)
    yield hold, self, self.items* Itemtime
    leaving = Now ()     # Customer completes purchase
    checkouttime.tally (leaving-at_checkout)
    Yield release, self, Checkout_aisle

Each customer has decided to purchase a certain quantity of goods. (Our simulations do not involve the selection of goods from the grocery aisle; customers simply push their carts to the payment office.) I'm not sure that the exponential distribution here is really a precise model. I feel right at the bottom of the list, but I feel a bit untrue about the maximum amount of merchandise that the actual shopper is purchasing. In any case, you can see how easy it is to adjust our simulations if you can use better model information.

The actions taken by the customer are our concern. The customer's "method of Execution" is. Checkout (). This process method is usually named. Run () or. Execute (), but in my example,. Checkout () seems to be the most descriptive. You can have any name you want on it. The actual action taken by the Customer object is simply to check the simulation time at several points and to record the duration in the waittime and checkouttime monitoring programs. However, between these operations is a vital yield statement. In the first case, the customer requests the resource (the payment channel). Only when the customer has acquired the required resources can they do other things. Once in the payment aisle, the customer is actually paying-the time spent is proportional to the number of items purchased. Finally, after the payment office, the customer releases the resources so that other customers can use it.

The above code defines the operation of the customer class, but we need to create some actual customer objects before running the simulation. We can generate customer objects for each customer who will be shopping for the day and allocate the appropriate payment time for each customer. But the more concise approach is to have the factory object generate the customer objects that are needed when each customer comes to the store. In fact, the simulations are not at the same time interested in all the customers who will be shopping in one day, but only for those customers who are competing for the payment channel at the same time. Note: The Customer_factory class itself is part of the simulation-it is a process. Although you might associate the man-made machine worker (Metropolis of La Fritz Lang) with this client factory, you should think of it as a handy tool for programming only; it does not directly correspond to anything in the modeled domain.
Listing 4. Generate Customer Flow

Class Customer_factory (simulation.process):
  def run (self): while
    1:
      c = Customer ()
      Simulation.activate (c, C.checkout ())
      arrival = Random.expovariate (float (avgcust)/closing) yield hold
      , self, Arrival

As I mentioned earlier, I want to collect some statistics that are not resolved by the current SimPy Monitor class. That is, I am not only interested in average payment time, but also in the worst-case scenario for a given scenario. So I created an enhanced monitoring program that collects the minimum and maximum count values.
Monitoring simulations with monitoring programs

Class Monitor2 (Monitor):
  def __init__ (self):
    monitor.__init__ (self)
    self.min, Self.max = (int (2**31-1), 0
  def tally (self, x):
    monitor.tally (self, x)
    self.min = min (self.min, x)
    Self.max = max (Self.max, X)

The final step of our simulation is of course to run it. In most standard examples, only one impersonation is run. But for my grocery store, I decided to cycle through several simulations each time to correspond to the business of one day. This seems to be a good idea, because some statistics vary considerably from one day to the other (because the number of customers arriving and the amount of merchandise purchased is randomly produced by different values).
Listing 6. Run the simulation every day

For run in range (runs):
  waittime = Monitor2 ()
  checkouttime = Monitor2 ()
  Checkout_aisle = Simulation.resource (aisles)
  simulation.initialize ()
  CF = Customer_factory ()
  simulation.activate (cf, Cf.run (), 0.0)
  simulation.simulate (until=closing)
  #print "Customers:", Checkouttime.count ()
  Print Waiting time average:%.1f "% waittime.mean (), \
     " (Std dev%.1f, maximum%.1f) "% (sqrt (Waittime.var ()), Waittime.max)
  #print "Checkout time average:%1f"% checkouttime.mean (), \
  #   "(Standard deviation%.1f)"% sqrt (Checkou Ttime.var ())
print ' aisles: ', aisles, ' ITEM time: ', itemtime


Three people are not happy: some results (and what they mean)

When I first considered the grocery store model, I thought simulations could answer a few immediate questions. For example, I imagine that shopkeepers might choose to buy improved scanners (reduce itemtime) or hire more staff (add aisles). I want to run this simulation under each scenario (assuming that the employee and technical costs are given) and determine which of the two options is more cost-reducing.

Only after running the simulation did I realize that there might be more interesting things than expected. Looking at all the data collected, I realized I didn't know what to try to optimize. What the. Which is more important, for example, to reduce the average payment time and minimize the time of the worst? What areas will improve overall customer satisfaction? In addition, how do you compare the waiting time that a customer spends before payment and the time it takes to scan a product? In my personal experience, I will be impatient in waiting queues, but I won't be bothered when scanning my product (even if it takes some time).

Of course, I don't run a grocery store, so I don't know the answers to all these questions. But this simulation really makes me decide exactly what a compromise is, and it's simple enough to adjust to a lot of behaviors, including those that haven't been explicitly parameterized-for example, "Does the customer really keep coming all day?" ”)。

I just want to demonstrate the value of the model by showing the last example. I have written above that the behavior of complex systems is difficult to conceptualize. I think the example here can prove this fact. What do you think will happen when the available channels are reduced from 6 to 5 (other parameters are unchanged)? Initially I would like to increase the payment time in the worst-case scenario slightly. And that is not the case:
Listing 7. Two samples running before and after the change of channel number

% python market.py waiting time average:0.5 (Std dev 0.9, maximum 4.5) waiting time Avera  ge:0.3 (Std dev 0.6, maximum 3.7) waiting time average:0.4 (Std dev 0.8, maximum 5.6) waiting time average:0.4 (Std dev 0.8, maximum 5.2) waiting time average:0.4 (Std dev 0.8, maximum 5.8) waiting time average:0.3 (Std dev 0.6, maximum 5. 2) Waiting time average:0.5 (Std dev 1.1, maximum 5.2) waiting time average:0.5 (Std dev 1.0, maximum 5.4) Aisles:6 IT EM time:0.1% python market.py waiting time average:2.1 (Std dev 2.3, maximum 9.5) waiting time average:1.8 (Std dev 2. 
3, Maximum 10.9) waiting time average:1.3 (Std dev 1.7, maximum 7.3) waiting time average:1.7 (Std dev 2.1, maximum 9.5) Waiting time average:4.2 (Std dev 5.6, maximum 21.3) waiting time average:1.6 (Std dev 2.6, maximum 12.0) waiting time average:1.3 (Std dev 1.6, maximum 7.5) waiting time average:1.5 (Std dev 2.1, maximum 11.2) aisles:5 ITEM time:0.1 /pre> 

Reducing a payment channel is not to increase the average wait time by 1/5 or something like that, but to increase it by about 4 times times. Moreover, the waiting time for the most unfortunate customers (during these specific runs) increased from 6 minutes to 21 minutes. If I were a manager, I think understanding this limit is extremely important to customer satisfaction. Who would have known that already?

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.