from Import def test1 (): print gr2.switch () Print def test2 (): print gr1.switch ()print == Greenlet ( test2) Gr1.switch ()
This creates two Greenlet, Gr1 and GR2, respectively, corresponding to the function test1 () and Test2 (). Using the switch () method of the Greenlet object, you can toggle the co-process. In the above example, we first call "Gr1.switch ()", the function test1 () is executed, and then print out "12″", and then because "Gr2.switch ()" is called, the co-process switches to the function test2 (), printing out "56″;" Gr1.switch () " is called again, so switch to function test1 (). Note, however, that since the previous test1 () has been executed to line 5th, that is, "Gr2.switch ()", the switch back will continue to execute, that is, print "34″; now the function test1 () exits, and the program exits. Since there is no "gr2.switch ()" To switch to function test2 (), the 11th line of the program "Print 78″ will not be executed.
125634
Parent-child Relationship
There are actually two parameters for creating a co-object (Greenlet (Run=none, Parent=none)). The parameter "Run" is the method to be called, such as the function test1 () and Test2 () in the previous example, and the parameter "parent" defines the parent of the process object, that is to say, there can be a parent-child relationship between the Greenlet threads. If not or set to NULL, then its parent is the program's default "main" main coprocessor. This "main" process does not require user creation, the corresponding method is the main program, and all user-created association is its descendants. You can think of the Greenlet set as a tree, the root node of the tree is "main", the above example "Gr1″ and" Gr2″ is its two-byte point.
The parent process is returned automatically when the child coprocessor finishes executing. For example, the Test1 () function exits in the previous example, and the code returns to the main program. Let's write a clearer example to experiment with:
from Import def test1 (): print gr2.switch () Print def test2 (): print greenlet== test2, Gr1) gr1.switch ()print 78
When you create the Greenlet object "Gr2″, it specifies that its parent is" Gr1″. So in the function test2 (), although there is no "gr1.switch ()" Code, but after it exits, the program returns to the function Test1 () and executes "print 34″." Similarly, after test1 () exits, the code goes back to the main program and executes "Print 78″." So, the final output is:
12563478
If, in the example above, "Gr2″ 's parent is not" Gr1″ but "main", then the Test2 () will go back to the main program and print "78″ so that" print 34″ will not execute. You can have a try.
Another important point is that after the process exits, it can no longer be executed. If the above example is in the function test1 (), add a "gr2.switch ()", the result of the operation is the same. Nothing will run because the second call is "Gr2.switch ()".
def test1 (): print gr2.switch ()print gr2.switch ()
You may feel the relationship between father and son, just like a function call, a nested one. Indeed, in fact, the implementation of the Greenlet process is to use the stack, its running context is stored in the stack, "main" main process is at the bottom of the stack, and the current running of the process is at the top of the stack. This is the same as the function. In addition, at any time, you can use "greenlet.getcurrent ()" To get the currently running Coprocessor object. For example, "greenlet.getcurrent ()" is executed in function test2 (), and its return is equal to "Gr2″."
Abnormal
Since the co-process is stored in the stack, the one that throws the exception is thrown into its parent, and the program exits if none of the parent threads catches the exception. Let's try to change the code of Function Test2 () in the example above to:
def test2 (): print raise nameerror
After the program executes, we can see the Traceback information:
" parent.py " inch gr1.switch () "parent.py" in test1 Gr2.switch () "parent.py" in test2 Raise Nameerror
If the Gr2″ parent Cheng is empty, the Traceback information becomes:
" parent.py " inch gr1.switch () "parent.py" in test2 Raise Nameerror
Therefore, if the Gr2″ parent is Gr1″, the exception is thrown back to the Code "Gr2.switch ()" of the function test1 (). So, let's change the function test1 () again:
def test1 (): print try: gr2.switch () except nameerror: Print print 34
After running the result, if the "Gr2″ parent is" Gr1″, then the exception is caught and printed 90. Otherwise, the exception is thrown. The above experiment proves very well that the exception thrown by the sub-association will be thrown into the parent's process according to the order in the stack.
An exception is a special case and will not be thrown into the parent's path, which is "Greenlet." Greenletexit ", this exception causes the current process to force exit. For example, let's change the function test2 () to:
def test2 (): print raise Greenlet. Greenletexit print 78
That code line "Print 78″ will never be executed." But this exception is not thrown up, so the parent can still run normally
In addition, we can use the Greenlet object's "throw ()" method to manually throw an exception to a co-thread. For example, we have a throw () method in Test1 ():
def test1 (): print gr2.throw (nameerror)try: gr2.switch () Except nameerror: print print 34
This way, the exception is thrown, and the trackback after the run:
" exception.py " inch gr1.switch () "exception.py" in test1 Gr2.throw (Nameerror)
If you put "Gr2.throw (Nameerror)" In the "try" statement, the exception is captured and printed "90″." Also, when the Gr2″ parent is not Gr1″ but "main", the exception is thrown directly into the main program, where the "try" statement in function test1 () does not work.
Passing messages between threads
When we introduced the generator, we talked about using the generator's send () method to pass parameters. Greenlet is also supported, as long as its switch () method is called, the parameters can be passed in. Let's do it again. Based on the first example of this article:
from greenlet import Greenlet def Test1 (): print 12 y = Gr2.switch (56) print y Span style= "COLOR: #0000ff" >def Test2 (x): Print x gr1.switch ( 34 print 78 Gr1 = Greenlet ( test1) gr2 = Greenlet (test2) gr1.switch ()
Called "Gr2.switch ()" in Test1 (), the incoming parameter "56″" is assigned to the parameter "x" of the Test2 () function because it was not started before Gr2″, and "test2 ()" is called in Gr1.switch (), because the co-process "Gr1″ Previously executed to line 5th "y = Gr2.switch (56)" Here, so the passed parameter "34″" is assigned to the variable "y" as the return value of "Gr2.switch (56)". In this way, the mutual communication between the two processes is realized.
The example of producer consumers, instead of greenlet implementation:
fromGreenletImportGreenletdefconsumer (): last="' whileTrue:receival=Pro.switch (last)ifReceival is notNone:Print 'Consume%s'%Receival Last=receivaldefproducer (n): Con.switch () x=0 whileX <n:x+ = 1Print 'Produce%s'%x Last=Con.switch (x) Pro=Greenlet (producer) Con=Greenlet (consumer) Pro.switch (5)
Using Greenlet to implement concurrency in Python