Python's high performance programming process

Source: Internet
Author: User

handling asynchronous events with the Greenlet process

Since Pycon 2011 has become a hot topic, I have been interested in it. In order to be asynchronous, we used multithreaded programming. However, the thread's performance bottleneck in the GIL Python and the high error risk of multithreaded programming, the combination of "coprocessor + multi-process" is gradually considered to be the direction of future development. Technology is easy to update, but thinking shifts requires a transition. I have been accustomed to the asynchronous event processing in the callback + multi-threaded thinking mode, the transition to the process is also very not suitable. These days I looked very hard at some of the information and thought about it and came up with a potentially unreliable summary. Although the reliability of this summary is questionable, I decided to record it because I think that since it is a learner, I should not be afraid of ignorance. I would appreciate it if the reader found my opinion to be biased and pointed out.

the way of asynchronous programming under multi-thread

async processing is based on two prerequisites. The first premise is to support concurrency, which is, of course, the basic premise. Concurrency here does not have to be parallel, that is, to allow the logical asynchronous, implementation on the serial, the second premise is to support callbacks (callback), because the concurrent, asynchronous processing does not block the currently executing process, so "after the completion of the task" to perform the steps should be written in the callback, Most callbacks are implemented through functions.

Multithreading is suitable for asynchronous programming because it supports both concurrency and callbacks. Both system-level threads and user-level threads can logically execute different control flows concurrently, and because of the ability to share in-process resources, callbacks only need to pass through simple callback functions.

Because of the messy handling of callback functions, the general asynchronous program introduces an event mechanism. This means that a series of callback functions are registered to a named event, and when the event is triggered, the callback functions are executed. For example, in ECMAScript, after accessing the remote URL, you need to populate the page with the results of the response, in the case of synchronization (blocking):

Open the homepage of the Watercress page//Open a firebut/chrome console test var http = new XMLHttpRequest ();//The third parameter is false to indicate that the asynchronous Http.open is not used ("GET", " /site ", false);//Send Request Http.send ();//fill response, one second change page document.write (http.response);

It is very simple to handle because the XMLHttpRequest send method blocks the main thread, so we must have completed the remote access when we went to read the http.response. What if you use asynchronous methods based on multithreading and callback functions? Problems can get a lot of trouble:

var http = new XMLHttpRequest (); Http.open ("GET", "/site", true);//You must now use the callback function Http.onreadystatechange = function () {
if (http.readystate = = http. Done) {
if (Http.status = = 200) {
document.write (Http.response);
}
} else if (http.readystate = = http. LOADING) {
document.write ("Loading <br/>");
}};http.send ();

The onreadystatechange callback function must be set because the Send method no longer blocks the main thread after using asynchronous mode. XMLHttpRequest has multiple loading states, and each state change invokes a user-set callback function. Programming now becomes cumbersome, but the user experience gets better because the main thread is no longer blocked, and the user can see the "loading" prompt, and other things can be done asynchronously during this time. In order to simplify the use of callback functions, there are generally two ways to improve the callback, the first is to simple callbacks, directly in the parameters of the callback function, which is convenient for languages with anonymous functions (such as ECMAScript and Ruby, obviously C and Python are not) The second way is for complex callbacks to be replaced with the event manager. Is still an example of an AJAX request, the package provided by jquery takes the first approach:

$.get ("/site", function (response) {
document.write (Http.response);});

The browser window object, as specified by the Web, takes the event manager to manage more complex asynchronous support:

Do not try under IE, IE's function name is not the same. Window.addeventlistener ("Load", function () {
Do something}, false);

the nature of the event manager is to use callbacks, but this approach puts forward the concept of "event", which is to register the callback function uniformly in a manager, and correspond to the respective "events", when this series of callback functions need to be called, "trigger" the "event", The manager invokes the callback function that is registered in. This approach unlocks the coupling between the caller and the callee, which is actually a specific application of the GoF Observer pattern [0] .

using multithreading to realize the disadvantage of asynchrony
"We still think that no one can write the right program in a language where even a=a+1 have no definite results." "The Soul of Programming" [1]

serial threads are not able to take full advantage of multicore resources, but thread safety seems to be a wise choice, but Python's threads have a big drawback-these threads are system-level. System-level threads are dispatched by the kernel, and the overhead of scheduling is larger than expected, and in many cases these scheduling costs are not worth the effort. For example, an asynchronous remote URL acquisition, originally only need to start access to the network when the main thread control, get a response to return to the main thread control, after the use of system-level threads to dispatch all delegated to the system kernel, simple problems are often complicated. The Coroutine [2] provides a different way from threading, which is first serialized. Second, during serialization, the process allows the user to explicitly release control and transfer control over another process. After releasing control, the state of the original process is preserved until control is restored and can continue. Therefore, the control transfer of the process is also called "Suspend" and "Wake Up".

co-processes in Python

 .

A simple event scheduling model can be implemented using the generator as a co-process support:

From time import sleep# Event managerevent_listeners = {}def fire_event (name):
Event_listeners[name] () def use_event (func):
def call (*args, **kwargs):
Generator = func (*args, **kwargs)
# Execute to Pending
Event_Name = Next (Generator)
# registering "Wake-up Pending" in the event manager
Def resume ():
Try
Next (Generator)
Except stopiteration:
Pass
Event_listeners[event_name] = Resume
return call# [email protected]_eventdef test_work ():
Print ("=" * 50)
Print ("Waiting Click")
Yield "Click" # suspends the current thread, waits for an event
Print ("Clicked!") if __name__ = = "__main__":
Test_work ()
Sleep (3) # Doing a lot of other things
Fire_event ("click") # triggers the Click event

The test run can see that after printing out "waiting Click", it pauses for three seconds, that is, the process is suspended, control is returned to the main control flow, and then the "click" event is triggered, and the process is awakened. This "suspend" and "wake" mechanism of the process essentially divides a procedure into several sub-processes, giving us a flat way to use the event callback model.

implement simple event framework with Greenlet

The implementation of the association with the generator is a bit cumbersome, and the generator itself is not a complete implementation of the process, so it is often criticized that Python's process is weaker than Lua. In fact, in Python just drop the generator, using the third-party library Greenlet, it can be comparable to Lua's native association. Greenlet provides a way to switch control directly in the process, which is more flexible and concise than the generator.

I used Greenlet to create a simple event framework, based on the view that the association was seen as a "cut-off callback."

From Greenlet import Greenlet, Getcurrentclass Event (object):
def __init__ (self, name):
Self.name = Name
Self.listeners = set ()

def listen (self, listener):
Self.listeners.add (Listener)

def fire (self):
For listener in Self.listeners:
Listener () class EventManager (object):
def __init__ (self):
Self.events = {}

def register (self, name):
Self.events[name] = Event (name)

def fire (Self, name):
Self.events[name].fire ()

def await (self, event_name):
Self.events[event_name].listen (GetCurrent (). switch)
GetCurrent (). Parent.switch ()

def use (self, func):
Return Greenlet (func). switch

With this event framework, it is easy to complete the steps for the wake-up process, such as the suspend process, transfer control, and event triggering. Or the example used in the Generator association above, implemented using the Greenlet-based event framework:

From time import sleepfrom event Import eventmanagerevent = EventManager () event.register ("click") @event. Usedef Test ( Name):
print "=" * 50
Print "%s Waiting click"% Name
Event.await ("click")
Print "Clicked!" if __name__ = = "__main__":
Test ("Micro-thread")
Print "Do many other works ..."
Sleep (3) # do many other works
Print "Done ... now trigger click event."
Manager.fire ("click")

Similarly, the results of the operation are as follows:

==================================================
Micro-thread Waiting Click
Do many other works ...
Done ... now trigger click event.
Clicked!!

After the "Do can other works" is printed out, control is cut out from the co-process, pausing for three seconds until the event click is triggered to re-plunge into the process.

Non-Python field, there is a called Jscex [4] Library implements similar co-ECMAScript functions in the absence of a co-process, and controls events.

Summary

Overall, I personally feel that the process has given us a more lightweight approach to asynchronous programming. In this way, there is no complicated system-level thread, no error-prone critical resources, but a more transparent way--explicit switch control instead of scheduler full of "guessing" scheduling algorithm, discard in-process concurrency using a clear serial method. In combination with multi-process, I think the application of the association in asynchronous programming, especially Python asynchronous programming, will be more and more extensive.


Python's high performance programming process

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.