The greenlet I looked at before only provides the basic function of coroutine and is the smallest execution unit. But if you want to use it, you also need to provide a scheduler to schedule when which greenlets should be executed. So I took a look at the implementation of gevent. Currently, The stable version uses an alternative to libev.libevent. The performance is superior. libev supports many event types, but the most commonly used ones are io and timer types. The io type is implemented through related system calls provided by the system ( epoll under Linux), the timer type is implemented by maintaining a minimum heap.
Look at the following code:
Python code
import gevent from gevent import monkey monkey.patch_all() def download(): import urllib2 urllib2.urlopen('http://www.google.com/').read() c = gevent.spawn(download) gevent.joinall([c])
gevent creates and starts a greenlet through spawn, and the greenlet execution function is download. Start this greenlet This is done by adding this greenlet to libev's prepare callback. Libev will call the function in prepare callback every time the event loop is executed, and clear the callback inside after execution. This ensures that the greenlet of spawn is executed every time. opportunity. And it will only be executed once.
When this greenlet executes urlopen and read, because it involves io operations (socket.[send|recv]), gevent encapsulates these functions through monkey patch. When calling the relevant During the operation, a watcher corresponding to fd will be created and added to the event list of libev.
When a relevant read and write event occurs, the corresponding callback will be triggered. The relevant callback will call the greenlet switch to switch the coroutine.
By In the above way, greenlet achieves the purpose of the scheduler.