Transferred from: Http://www.leeon.me/a/use-Psyco-to-improve-Python-speed
Psyco is strictly operational when Python is running. That is, the Python source code is compiled into bytecode via Python commands in exactly the same way as before (except for several import statements and function calls added to call Psyco). However, when the Python interpreter runs the application, Psyco checks from time to times to see if it can replace the regular Python bytecode operation with some specialized machine code. This specialized compilation is very similar to what the Java Instant compiler does (generally speaking, at least), and is architecture-specific. Until now, Psyco is only available for I386 CPU architectures. The beauty of Psyco is that you can use the Python code you've been writing (exactly the same!). ), but it can make it run faster.
How the Psyco works
To fully understand Psyco, you may need to have a good grasp of the Python interpreter's Eval_frame () function and i386 assembly language. Unfortunately, I am not able to make an expert opinion on any of them-but I think I can outline Psyco in general.
In regular Python, the Eval_frame () function is the inner loop of the Python interpreter. The Eval_frame () function primarily looks at the current bytecode in the execution context and switches the control outward to a function that is appropriate for implementing the bytecode. The specifics of what the support function will do usually depend on the state of the various Python objects that are stored in memory. Simply put, adding Python objects "2" and "3" and adding Objects "5" and "6" produce different results, but both operations are dispatched in a similar way.
Psyco replaces the Eval_frame () function with a composite evaluation unit. There are several ways Psyco can be used to improve the operation of Python. First, Psyco compiles the operation into a somewhat optimized machine code; Because the machine code needs to do the same thing as the Python dispatch function, there is only a slight improvement in itself. Furthermore, the "specialized" content in Psyco compilation is not only the choice of Python bytecode, but also the Psyco of the variable values known in the execution context. For example, in code similar to the following, the variable x is known for the duration of the loop:
x = 5
L = []
For I in range (1000):
L.append (X*i)
The optimized version of the code does not need to use the "X variable/object Contents" by each I, compared with the simple 5 times each I use less overhead, omit the Find/indirect reference this step.
In addition to creating i386-specific code for small operations, Psyco caches this compiled machine code for future reuse. If Psyco is able to identify a particular operation as it did earlier ("specialized"), it can rely on the cached code without having to compile the code snippet again. This saves some time.
However, the real time-saving reason in Psyco is that Psyco divides the operation into three different levels. For Psyco, there are "runtime", "compile-time", and "virtual-time" variables. Psyco increase and decrease the level of variables as needed. Run-time variables are just raw bytecode and object structures that are processed by the regular Python interpreter. Once Psyco compiles the operation into a machine code, the compile-time variable is represented in the machine register and in the memory location where it can be accessed directly.
The most interesting level is the virtual time variable. Internally, a Python variable is a complete structure with many members-even when the object represents only an integer. Psyco virtual time variables represent Python objects that might be built when needed, but the details of these objects are ignored before they become Python objects. For example, consider the following assignment:
x = 15 * (14 + (13-(12/11)))
Standard Python constructs and destroys many objects to calculate this value. Construct a complete integer object to hold (12/11) This value, then "pull" a value from the structure of the temporary object and use it to calculate the new temporary object (13-pyint). Instead, Psyco skips these objects and computes only those values because it knows "if needed" and can create an object from the value.
using Psyco
Explaining Psyco is relatively difficult, but using Psyco is easy. Basically, it's all about telling the Psyco module which function/method to "specialize". Any Python function and the code of the class itself are not subject to change.
There are several ways to specify what Psyco should do. The shotgun (shotgun) method makes it possible to use Psyco instant operations anywhere. To do this, place the following lines at the top of the module:
Import Psyco; Psyco.jit ()
From psyco.classes Import *
The first line tells Psyco to "play its magic" on all global functions. The second line (in Python 2.2 and later) tells Psyco to perform the same action on the class method. To more precisely determine the behavior of Psyco, you can use the following commands:
Psyco.bind (SomeFunc) # or method, class
newname = Psyco.proxy (func)
The second form takes Func as the standard Python function, but optimizes calls involving NewName. In almost all cases except testing and debugging, you will use the Psyco.bind () Form.
Performance of Psyco
Although Psyco is so magical, using it still requires a little thought and testing. The main point is to understand that Psyco is useful for handling chunks of multiple loops, and it knows how to optimize operations involving integers and floating-point numbers. For operations of non-cyclic functions and other types of objects, Psyco mostly only increases the overhead of parsing and internal compilation. Also, for applications with a large number of functions and classes, enabling Psyco throughout the application scope adds a lot of burden to machine code compilation and memory usage for this cache. It is much better to selectively bind functions that can derive the most benefit from Psyco optimizations.
I started my testing process in a very naïve way. I have only considered applications that I have run recently, but that have not yet been considered for acceleration. The first example that comes to mind is a text manipulation program that converts my forthcoming manuscript (Text processing in Python) into LaTeX format. The application uses some string methods, some regular expressions, and some program logic driven primarily by regular expressions and string matching. It's a bad choice to actually use it as a test candidate for Psyco, but I'm still using it, and that's how it started.
in the first test, all I did was add Psyco.jit () to the top of the script. It doesn't take any effort. Unfortunately, the results (expected) are disappointing. The original script will take 8.5 seconds to run, and it will run for about 12 seconds after the Psyco "acceleration". It sucks! I suspect that the startup overhead required for immediate compilation is a drag on the run time. So next I try to process a larger input file (consisting of multiple copies of the original input file). This time it was a small success, which reduced the running time from about 120 seconds to 110 seconds. The acceleration effect in several runs is consistent, but the effect is not significant.
The second pass test of this processing candidate. I only added the Psyco.bind (main) line instead of adding a total Psyco.jit () call, because the main () function does have to loop multiple times (but only with the least number of integer operations). The results here are nominally better than before. This method cuts the normal run time by a few seconds and cuts it for a few seconds in the case of a larger input version. But there is still no noticeable result (but no harm).
For a more appropriate Psyco test, I searched for some of the neural network codes I wrote in previous articles (see Resources). This code recognizer (Code_recognizer) application can be trained to identify possible distributions of different ASCII values written in different programming languages. Something like this might be useful in guessing the type of file (for example, a lost network packet), but in terms of what to "train", the code is actually completely generic-it can easily learn to recognize faces, sounds, or tidal patterns. In any case, the code recognizer is based on the Python Library Bpnn,psyco 4.0 distribution which also contains (in the form of remediation) the library as a test case. In this article, it is important to understand that the code recognizer does many floating-point arithmetic loops and takes a long time to run. Here we have a good candidate use case that can be used for PSYCO testing.
After using it for a while, I established some details about the usage of Psyco. For applications with only a small number of classes and functions, there is not much difference between using an instant binding or a target binding. But the best result is that you can still get a few percent improvements by selectively binding the optimization class. However, it is important to understand the scope of the Psyco binding.
The code_recognizer.py script includes these lines similar to the following:
Importing NN from BPNN
Class NN2 (NN):
# Customized output methods, math core inherited
In other words, from Psyco's point of view, interesting things are in class bpnn.nn. adding Psyco.jit () or Psyco.bind (NN2) to the code_recognizer.py script does not work. For Psyco to perform the desired optimizations, you need to add Psyco.bind (NN) to the code_recognizer.py or add Psyco.jit () to bpnn.py. In contrast to what you might assume, immediate optimization does not occur when the instance is created or when the method runs, but rather within the scope of the definition class. In addition, bound derived classes do not specialize in methods that they inherit from elsewhere.
Once the details of the appropriate Psyco bindings are found, the acceleration effect is quite obvious. Using the same test cases and training methods provided in the reference article (500 training modes, 1000 training iterations), the neural network training time has been reduced from about 2000 seconds to about 600 seconds-up to 3 times times faster. The number of iterations is reduced to 10, and the speedup is scaled down (but the ability to recognize the neural network is not valid), and the median value of the iteration changes as well.
I found that using two lines of new code can reduce the run time from more than half an hour to about 10 minutes, the effect is very significant. This acceleration may still be slower than a similar application written by C, and it is certainly slower than the 100 times-fold acceleration reflected by several independent Psyco test cases. But this kind of application is quite "real", and in many environments these improvements have been significant enough.
"Go" uses Psyco to boost Python's running speed