1

I am new to async programming. I am doing a small POC where I want to see how greenlets behave with shared objects. I have written this code -

from gevent import monkey, sleep
from gevent import Greenlet
monkey.patch_all(thread=False, socket=False)

class Events:
    def __init__(self):
        self.num = 0
        self.limit = 10
        self.bulk_records = []

    def start(self, task_number=0):
        count = 0
        print("Task: %s started" % task_number)
        while count != 10:
            self.bulk_records.append(task_number)
            sleep(0.1)
            if len(self.bulk_records) == self.limit:
                print("%s, Task %s, outputting list: %s" % (self.num, task_number, self.bulk_records))
                self.bulk_records[:] = []
                self.num += 1
            count += 1
        print("Task - %s, count - %s" % (task_number, count))

def run_test():
    event = Events()
    tasks = [Greenlet.spawn(event.start, i) for i in range(5)]
    print("Num tasks - %s" % len(tasks))
    [task.run() for task in tasks]
    print("End")

if __name__ == '__main__':
    run_test()

It gives the following output:-

Num tasks - 5
Task: 0 started
Task: 1 started
Task: 2 started
Task: 3 started
Task: 4 started
0, Task 0, outputting list: [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
1, Task 0, outputting list: [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
2, Task 0, outputting list: [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
3, Task 0, outputting list: [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
4, Task 0, outputting list: [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
Task - 0, count - 10
Task: 1 started # This is not expected
Task - 1, count - 10
Task - 2, count - 10
Task - 3, count - 10
Task - 4, count - 10
5, Task 1, outputting list: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Task - 1, count - 10
End

Process finished with exit code 0

The code works as expected but in the end something weird happened, Task 1 is started again and the corresponding function start is executed again.

Not sure if this is a valid behavior, or what I am missing in the code to prevent Greenlet to start again.

Thanks is advance

dirn
  • 19,454
  • 5
  • 69
  • 74
Anurag Sharma
  • 4,839
  • 13
  • 59
  • 101
  • Had a quick look, I don't have any explanation except that this might be a bug in greenlet/gevent... It seems unlikely such a bug wouldn't have been discovered though? What version of Python are you using? Is it also your understanding that the greenlets yield on the calls to `print`? – jwg Sep 25 '17 at 08:10
  • 1
    this call ` [task.run() for task in tasks]` is wrong ; what is it for? `spawn` already runs greenlets. You want to wait until execution of greenlets is done using `gevent.joinall(tasks)`. Do not call 'run' directly. – mguijarr Jan 11 '20 at 13:54
  • Hello @mguijarr, kindly post this as an answer and I will accept this. The solution provided by you works. Thanks – Anurag Sharma Jan 14 '20 at 03:29

1 Answers1

1

Contrary to the thread API, which requires a thread object to be created and to call the start() method, gevent.spawn does both greenlet instantiation and schedules the greenlet to run in one call.

So, calling run() on greenlet objects is not needed (and probably very wrong in most cases).

Waiting for tasks to be completed is done with joinall(list of greenlets). After this call, all greenlets are ready (dead, successfully or not).

mguijarr
  • 7,641
  • 6
  • 45
  • 72