This simulation is adapted from the Bank Renege example in Simjulia documentation: http://simjuliajl.readthedocs.io/en/stable/examples/1_bank_renege.html
using SimJulia
using Distributions
using RandomStreams
Let's first simulate a fixed number of clients.
const RANDOM_SEED = 200
const NEW_CUSTOMERS = 5 # Total number of customers
const INTERVAL_CUSTOMERS = 2.0 # Generate new customers roughly every x seconds
const MEAN_SERVICE = 1.9
function source(env::Environment, number::Int, interval::Float64, counter::Resource)
d = Exponential(interval)
for i in 1:number
yield(Timeout(env, rand(d)))
Process(env, customer, i, counter, MEAN_SERVICE)
end
end
function customer(env::Environment, idx::Int, counter::Resource, time_in_system::Float64)
# Record the arrival time in the system
arrive = now(env)
println("$arrive: arrival of customer $idx")
yield(Request(counter))
# The simulation clock now contains the time when the client goes to the server.
wait = now(env) - arrive
# Record the waiting time
waits[idx] = wait
println("$(now(env)): customer $idx has waited $wait")
yield(Timeout(env, rand(Exponential(time_in_system))))
println("$(now(env)): customer $idx: finished")
yield(Release(counter))
end
# Setup and start the simulation
println("M/M/1 with processes")
waits = Array(Float64, NEW_CUSTOMERS)
srand(RANDOM_SEED)
env = Environment()
# Start processes and run
counter = Resource(env, 1)
Process(env, source, NEW_CUSTOMERS, INTERVAL_CUSTOMERS, counter)
run(env)
We can compute the mean waiting time by
mean(waits)
However, most of the time, we do not know the number of client. We first set the end of simulation event by specifying an time horizon when running the simulation.
Process(env, source, NEW_CUSTOMERS, INTERVAL_CUSTOMERS, counter)
run(env, 5.0)
We observe however that the simulation time has not been reset to 0. A simple solution is to create a new simulation environment. This also requires to set the resource again.
env = Environment()
counter = Resource(env, 1)
Process(env, source, NEW_CUSTOMERS, INTERVAL_CUSTOMERS, counter)
run(env, 5.0)
The random draws are different but we can produce the same as previously by using the same seed, i.e. the same initial state.
srand(RANDOM_SEED)
env = Environment()
counter = Resource(env, 1)
Process(env, source, NEW_CUSTOMERS, INTERVAL_CUSTOMERS, counter)
run(env, 5.0)
However, a possible issue is that Customer 4 never finishes his service. If we want to allow the customer to complete his experience, we have to modify the source function. We can circumvent it by redefining the source function so that no customer is generated after a horizon limit, but we do not put a limit when calling the run function.
function source!(env::Environment, number::Int, interval::Float64, counter::Resource, limit::Float64, nserved::Array{Int64,1})
nserved[1] = 0
d = Exponential(interval)
for i in 1:number
yield(Timeout(env, rand(d)))
if (now(env) > limit) break end
Process(env, customer, i, counter, MEAN_SERVICE)
nserved[1] += 1
end
end
nserved = [ 0 ]
srand(RANDOM_SEED)
env = Environment()
counter = Resource(env, 1)
Process(env, source!, NEW_CUSTOMERS, INTERVAL_CUSTOMERS, counter, 5.0, nserved)
run(env)
This raises the question: should we flush the entities in the system at the end of the horizon of allow the entities in the system to complete their process? It depends on the context!
In our case, the mean waiting time is
mean(waits[1:nserved[1]])
function new_source!(env::Environment, interval::Float64, counter::Resource, limit::Float64, nserved::Array{Int64,1})
nserved[1] = 0
i = 0
d = Exponential(interval)
while (true)
yield(Timeout(env, rand(d)))
if (now(env) > limit) break end
i += 1
Process(env, new_customer, i, counter, MEAN_SERVICE, new_waits)
end
nserved[1] = i
end
function new_customer(env::Environment, idx::Int, counter::Resource, time_in_system::Float64, waits::Array{Float64,1})
# Record the arrival time in the system
arrive = now(env)
println("$arrive: arrival of customer $idx")
yield(Request(counter))
# The simulation clock now contains the time when the client goes to the server.
wait = now(env) - arrive
# Record the waiting time
waits = push!(waits, wait)
println("$(now(env)): customer $idx has waited $wait")
yield(Timeout(env, rand(Exponential(time_in_system))))
println("$(now(env)): customer $idx: finished")
yield(Release(counter))
end
nserved = [ 0 ]
srand(RANDOM_SEED)
env = Environment()
counter = Resource(env, 1)
new_waits = Float64[]
Process(env, new_source!, INTERVAL_CUSTOMERS, counter, 5.0, nserved)
run(env)
new_waits
nserved[1]