Multiple consumers of FilterStore - gets not occurring at correct times.

Issue #51 duplicate
Former user created an issue

I've noticed some odd behavior when multiple consumers are pulling different objects from a FilterStore. If there is only one active, the times are correct. When multiple are active, it seems that gets can become delayed.

Example code:

import simpy import random

class G: rnd = random.Random()

class ProdFacility: def init(self, env): self.env = env self.work = simpy.FilterStore(env) self.env.process(self.genStrings()) self.env.process(self.genInts()) self.env.process(self.handleStrings()) self.env.process(self.handleInts())

def genStrings(self):
    while True:
        yield self.env.timeout(G.rnd.expovariate(1.0/15))
        yield self.work.put("blah")
        print self.env.now, ": I put a string out there."

def genInts(self):
    while True:
        yield self.env.timeout(G.rnd.expovariate(1.0/12))
        n = G.rnd.randint(0,100)
        yield self.work.put(n)
        print self.env.now, ": I placed %d in the work queue." % (n)

def handleStrings(self):
    while True:
        # Wait for availability of a string
        item = yield self.work.get(filter=lambda x: isinstance(x,basestring))
        print self.env.now, ": Got %s" % (item)

def handleInts(self):
    while True:
        # Wait for availability of an int
        item = yield self.work.get(filter=lambda x: isinstance(x,int))
        print self.env.now, ": Oh yeah, baby!  I got a %d" % (item)

environment = simpy.Environment() prod = ProdFacility(environment) environment.run(until=100)

This code produces the following output:

10.0246844458 : I put a string out there. 10.0246844458 : Got blah 11.9496595933 : I put a string out there. 13.6354159669 : I placed 38 in the work queue. 13.6354159669 : Oh yeah, baby! I got a 38 13.6354159669 : Got blah 18.1796619402 : I put a string out there. 23.0254816531 : I placed 58 in the work queue. 23.0254816531 : Oh yeah, baby! I got a 58 23.0254816531 : Got blah 34.1235098467 : I placed 58 in the work queue. 34.1235098467 : Oh yeah, baby! I got a 58 39.6026866177 : I placed 40 in the work queue. 41.8115400727 : I put a string out there. 41.8115400727 : Got blah 41.8115400727 : Oh yeah, baby! I got a 40 45.5403570479 : I put a string out there. 45.5403570479 : Got blah 47.7281999965 : I placed 62 in the work queue. 47.7281999965 : Oh yeah, baby! I got a 62 55.7773513528 : I placed 95 in the work queue. 60.6119317946 : I placed 20 in the work queue. 76.7781109924 : I placed 94 in the work queue. 81.0468473533 : I placed 64 in the work queue. 81.0515478955 : I placed 43 in the work queue. 81.8829574406 : I put a string out there. 81.8829574406 : Got blah 81.8829574406 : Oh yeah, baby! I got a 95 81.8829574406 : Oh yeah, baby! I got a 20 81.8829574406 : Oh yeah, baby! I got a 94 81.8829574406 : Oh yeah, baby! I got a 64 81.8829574406 : Oh yeah, baby! I got a 43 90.3207860979 : I put a string out there. 90.3207860979 : Got blah

Comments (10)

  1. Jim Schreckengast

    I'm really sorry about the formatting. I should have hit "Preview" before posting it. I cannot reproduce the problem if I use a constant timeout of 1 in the generators. Here is the output:

    10.0246844458 : I put a string out there.
    10.0246844458 : Got blah
    11.9496595933 : I put a string out there.
    13.6354159669 : I placed 38 in the work queue.
    13.6354159669 : Oh yeah, baby!  I got a 38
    13.6354159669 : Got blah
    18.1796619402 : I put a string out there.
    23.0254816531 : I placed 58 in the work queue.
    23.0254816531 : Oh yeah, baby!  I got a 58
    23.0254816531 : Got blah
    34.1235098467 : I placed 58 in the work queue.
    34.1235098467 : Oh yeah, baby!  I got a 58
    39.6026866177 : I placed 40 in the work queue.
    41.8115400727 : I put a string out there.
    41.8115400727 : Got blah
    41.8115400727 : Oh yeah, baby!  I got a 40
    45.5403570479 : I put a string out there.
    45.5403570479 : Got blah
    47.7281999965 : I placed 62 in the work queue.
    47.7281999965 : Oh yeah, baby!  I got a 62
    55.7773513528 : I placed 95 in the work queue.
    60.6119317946 : I placed 20 in the work queue.
    76.7781109924 : I placed 94 in the work queue.
    81.0468473533 : I placed 64 in the work queue.
    81.0515478955 : I placed 43 in the work queue.
    81.8829574406 : I put a string out there.
    81.8829574406 : Got blah
    81.8829574406 : Oh yeah, baby!  I got a 95
    81.8829574406 : Oh yeah, baby!  I got a 20
    81.8829574406 : Oh yeah, baby!  I got a 94
    81.8829574406 : Oh yeah, baby!  I got a 64
    81.8829574406 : Oh yeah, baby!  I got a 43
    90.3207860979 : I put a string out there.
    90.3207860979 : Got blah
    

    The event of getting the text at 13.6354159669 should have occurred at 11.9496595933, unless I'm misunderstanding something about this.

    ```

  2. Jim Schreckengast

    Here is the code in the appropriate block (sorry about the formatting again).

    import simpy
    import random
    
    class G:
        rnd = random.Random()
    
    class ProdFacility:
        def __init__(self, env):
            self.env = env
            self.work = simpy.FilterStore(env)
            self.env.process(self.genStrings())
            self.env.process(self.genInts())
            self.env.process(self.handleStrings())
            self.env.process(self.handleInts())
    
        def genStrings(self):
            while True:
                yield self.env.timeout(G.rnd.expovariate(1.0/15))
                yield self.work.put("blah")
                print self.env.now, ": I put a string out there."
    
        def genInts(self):
            while True:
                yield self.env.timeout(G.rnd.expovariate(1.0/12))
                n = G.rnd.randint(0,100)
                yield self.work.put(n)
                print self.env.now, ": I placed %d in the work queue." % (n)
    
        def handleStrings(self):
            while True:
                # Wait for availability of a string
                item = yield self.work.get(filter=lambda x: isinstance(x,basestring))
                print self.env.now, ": Got %s" % (item)
    
        def handleInts(self):
            while True:
                # Wait for availability of an int
                item = yield self.work.get(filter=lambda x: isinstance(x,int))
                print self.env.now, ": Oh yeah, baby!  I got a %d" % (item)
    
    
    
    environment = simpy.Environment()
    prod = ProdFacility(environment)
    environment.run(until=100)
    
  3. Jim Schreckengast

    Here is a simpler, deterministic example.

    import simpy
    
    class SimpleDefect:
    
        def __init__(self, env):
            self.env = env
            self.store = simpy.FilterStore(env)
            self.env.process(self.producerA())
            self.env.process(self.producerB())
            self.env.process(self.consumerA())
            self.env.process(self.consumerB())
    
        def producerA(self):
            # Produces an 'A' for the store every 1 time unit
            while True:
                yield self.env.timeout(1.0)
                self.store.put('A')
                print self.env.now, ": Producer A fired event."
    
        def producerB(self):
            # Produces a 'B' for the store every 0.1 time units
            while True:
                yield self.env.timeout(0.1)
                self.store.put('B')
                print self.env.now, ": Producer B fired event."
    
        def consumerA(self):
            while True:
                # Wait for A's
                yield self.store.get(filter = lambda x : x == 'A')
                print self.env.now, ": Consumer A got an 'A'"
    
        def consumerB(self):
            while True:
                # Wait for B's
                yield self.store.get(filter = lambda x : x == 'B')
                print self.env.now, ": Consumer B got a 'B'"
    
    def main():
        env = simpy.Environment()
        bd = SimpleDefect(env)
        env.run(until=2)
    
    if __name__ == "__main__":
        main()
    

    This will generate the following output:

    0.1 : Producer B fired event.
    0.2 : Producer B fired event.
    0.3 : Producer B fired event.
    0.4 : Producer B fired event.
    0.5 : Producer B fired event.
    0.6 : Producer B fired event.
    0.7 : Producer B fired event.
    0.8 : Producer B fired event.
    0.9 : Producer B fired event.
    1.0 : Producer B fired event.
    1.0 : Producer A fired event.
    1.0 : Consumer A got an 'A'
    1.0 : Consumer B got a 'B'
    1.0 : Consumer B got a 'B'
    1.0 : Consumer B got a 'B'
    1.0 : Consumer B got a 'B'
    1.0 : Consumer B got a 'B'
    1.0 : Consumer B got a 'B'
    1.0 : Consumer B got a 'B'
    1.0 : Consumer B got a 'B'
    1.0 : Consumer B got a 'B'
    1.0 : Consumer B got a 'B'
    1.1 : Producer B fired event.
    1.2 : Producer B fired event.
    1.3 : Producer B fired event.
    1.4 : Producer B fired event.
    1.5 : Producer B fired event.
    1.6 : Producer B fired event.
    1.7 : Producer B fired event.
    1.8 : Producer B fired event.
    1.9 : Producer B fired event.
    
  4. Jim Schreckengast

    Version 3.04 behaves differently! It shows the same defect, except that it drops a number of consumer events. The output for the most recent example code produces the following:

    0.1 : Producer B fired event.
    0.2 : Producer B fired event.
    0.3 : Producer B fired event.
    0.4 : Producer B fired event.
    0.5 : Producer B fired event.
    0.6 : Producer B fired event.
    0.7 : Producer B fired event.
    0.8 : Producer B fired event.
    0.9 : Producer B fired event.
    1.0 : Producer B fired event.
    1.0 : Producer A fired event.
    1.0 : Consumer A got an 'A'
    1.0 : Consumer B got a 'B'
    1.1 : Producer B fired event.
    1.2 : Producer B fired event.
    1.3 : Producer B fired event.
    1.4 : Producer B fired event.
    1.5 : Producer B fired event.
    1.6 : Producer B fired event.
    1.7 : Producer B fired event.
    1.8 : Producer B fired event.
    1.9 : Producer B fired event.
    
  5. Ontje Lünsdorf

    Hi Jim,

    this issue is a duplicate of #49 and already fixed in the current tip. Here's the output I'm getting. This does look correct, isn't it?

    0.1 : Producer B fired event.
    0.1 : Consumer B got a 'B'
    0.2 : Producer B fired event.
    0.2 : Consumer B got a 'B'
    0.30000000000000004 : Producer B fired event.
    0.30000000000000004 : Consumer B got a 'B'
    0.4 : Producer B fired event.
    0.4 : Consumer B got a 'B'
    0.5 : Producer B fired event.
    0.5 : Consumer B got a 'B'
    0.6 : Producer B fired event.
    0.6 : Consumer B got a 'B'
    0.7 : Producer B fired event.
    0.7 : Consumer B got a 'B'
    0.7999999999999999 : Producer B fired event.
    0.7999999999999999 : Consumer B got a 'B'
    0.8999999999999999 : Producer B fired event.
    0.8999999999999999 : Consumer B got a 'B'
    0.9999999999999999 : Producer B fired event.
    0.9999999999999999 : Consumer B got a 'B'
    1.0 : Producer A fired event.
    1.0 : Consumer A got an 'A'
    1.0999999999999999 : Producer B fired event.
    1.0999999999999999 : Consumer B got a 'B'
    1.2 : Producer B fired event.
    1.2 : Consumer B got a 'B'
    1.3 : Producer B fired event.
    1.3 : Consumer B got a 'B'
    1.4000000000000001 : Producer B fired event.
    1.4000000000000001 : Consumer B got a 'B'
    1.5000000000000002 : Producer B fired event.
    1.5000000000000002 : Consumer B got a 'B'
    1.6000000000000003 : Producer B fired event.
    1.6000000000000003 : Consumer B got a 'B'
    1.7000000000000004 : Producer B fired event.
    1.7000000000000004 : Consumer B got a 'B'
    1.8000000000000005 : Producer B fired event.
    1.8000000000000005 : Consumer B got a 'B'
    1.9000000000000006 : Producer B fired event.
    1.9000000000000006 : Consumer B got a 'B'
    

    I guess Stefan will release the new version shortly.

    Cheers, Ontje

  6. Log in to comment