Movatterモバイル変換


[0]ホーム

URL:


Packt
Search iconClose icon
Search icon CANCEL
Subscription
0
Cart icon
Your Cart(0 item)
Close icon
You have no products in your basket yet
Save more on your purchases!discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Profile icon
Account
Close icon

Change country

Modal Close icon
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timerSALE ENDS IN
0Days
:
00Hours
:
00Minutes
:
00Seconds
Home> Programming> Object Oriented Programming> Advanced Python Programming
Advanced Python Programming
Advanced Python Programming

Advanced Python Programming: Accelerate your Python programs using proven techniques and design patterns , Second Edition

Arrow left icon
Profile Icon Quan Nguyen
Arrow right icon
₹799.99₹2800.99
Full star iconFull star iconFull star iconFull star iconHalf star icon4.6(14 Ratings)
eBookMar 2022606 pages2nd Edition
eBook
₹799.99 ₹2800.99
Paperback
₹3500.99
Subscription
Free Trial
Renews at ₹800p/m
eBook
₹799.99 ₹2800.99
Paperback
₹3500.99
Subscription
Free Trial
Renews at ₹800p/m

What do you get with eBook?

Product feature iconInstant access to your Digital eBook purchase
Product feature icon Download this book inEPUB andPDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature iconDRM FREE - Read whenever, wherever and however you want
Product feature iconAI Assistant (beta) to help accelerate your learning
OR

Contact Details

Modal Close icon
Payment Processing...
tickCompleted

Billing Address

Table of content iconView table of contentsPreview book icon Preview Book

Advanced Python Programming

Chapter 1: Benchmarking and Profiling

Recognizing the slow parts of your program is the single most important task when it comes to speeding up your code. In most cases, the code that causes the application to slow down is a very small fraction of the program. By identifying these critical sections, you can focus on the parts that need the most improvement without wasting time in micro-optimization.

Profiling is a techniquethat allows us to pinpoint the most resource-intensive parts of an application. Aprofiler is a program that runs an application and monitors howlong each function takes to execute, thus detecting the functions on which your application spends most of its time.

Python provides several tools to help us find these bottlenecks and measure important performance metrics. In this chapter, we will learn how to use the standardcProfile module and theline_profiler third-party package. We will also learn how to profile the memory consumption of an application through thememory_profiler tool. Another useful tool thatwe will cover isKCachegrind, which can be used to graphically display the data produced by various profilers.

Finally,benchmarks are smallscripts used to assess the total execution time of your application. We will learn how to write benchmarks and use them to accurately time your programs.

The topics we will cover in this chapter are listed here:

  • Designing your application
  • Writing tests and benchmarks
  • Writing better tests and benchmarks withpytest-benchmark
  • Finding bottlenecks withcProfile
  • Optimizing our code
  • Using thedis module
  • Profiling memory usage withmemory_profiler

By the end of the chapter, you will have gained a solid understanding of how to optimize a Python program and will be armed with practical tools that facilitate the optimization process.

Technical requirements

To follow the content of this chapter, you should have a basic understanding of Python programming and be familiar with core concepts such as variables, classes, and functions. You should also be comfortable with working with the command line to run Python programs. Finally, the code for this chapter can be found in the following GitHub repository:https://github.com/PacktPublishing/Advanced-Python-Programming-Second-Edition/tree/main/Chapter01.

Designing your application

In the early development stages, the design of a program can change quickly and may require large rewrites and reorganizations of the code base. By testing different prototypes withoutthe burden of optimization, you are free to devote your time and energy to ensure that the program produces correct results and that the design is flexible. After all, who needs an application that runs fast but gives the wrong answer?

The mantras that you should remember when optimizing your code are outlined here:

  • Make it run: We have to get the software in a working state and ensure that it produces the correct results. This exploratory phase serves to better understand the application and to spot major design issues in the early stages.
  • Make it right: We want to ensure that the design of the program is solid. Refactoring should be done before attempting any performance optimization. This really helps separate the application into independent and cohesive units that are easy to maintain.
  • Make it fast: Once our program is working and well structured, we can focus on performance optimization. We may also want to optimize memory usage if that constitutes an issue.

In this section, we will write and profile aparticle simulator test application. Asimulator is a program that considers some particles and simulates their movement over time according to a set of laws that we impose. These particles can be abstract entities or correspond to physical objects—for example, billiard balls moving on a table, molecules in a gas, stars moving through space, smoke particles, fluids in a chamber, and so on.

Building a particle simulator

Computer simulations are useful in fields such as physics, chemistry, astronomy, and many otherdisciplines. The applications used to simulate systems are particularly performance-intensive, and scientists and engineers spend an inordinate amount of time optimizing their code. In order to study realistic systems, it is often necessary to simulate a very high number of bodies, and every small increase in performance counts.

In our first example, we will simulate a system containing particles that constantly rotate around a central point at various speeds, just like the hands of a clock.

The necessary information to run our simulation will be the starting positions of the particles, the speed, and the rotation direction. From these elements, we have to calculate the position of the particle in the next instant of time. An example system is shown in the following diagram. The origin of the system is the(0, 0) point, the position is indicated by thex,y vector, and the velocity is indicated by thevx,vy vector:

Figure 1.1 – An example of a particle system

Figure 1.1 – An example of a particle system

The basic featureof a circular motion is that the particles always move perpendicular to the direction connecting the particle and the center. To move the particle, we simply change the position by taking a series of very small steps (which correspond to advancing the system for a small interval of time) in the direction of motion, as shown in the following diagram:

Figure 1.2 – Movement of a particle

Figure 1.2 – Movement of a particle

We will startby designing the application in anobject-oriented (OO) way. According to our requirements, it is natural to have a genericParticle classthat stores the particle positions,x andy, and their angular velocity,ang_vel, as illustrated in the following code snippet:

    class Particle:         def __init__(self, x, y, ang_vel):             self.x = x             self.y = y             self.ang_vel = ang_vel

Note that we accept positive and negative numbers for all the parameters (the sign ofang_vel will simply determine the direction of rotation).

Another class, calledParticleSimulator, will encapsulate the laws of motion and will be responsible for changing the positions of the particles over time. The__init__ method will store a list ofParticle instances, and theevolve method will change the particle positions according to our laws. The code is illustrated in the following snippet:

class ParticleSimulator:    def __init__(self, particles):        self.particles = particles

We want the particles to rotate around the position corresponding to thex=0 andy=0 coordinates, at a constant speed. The direction of the particles will always be perpendicular tothe direction from the center (refer toFigure 1.1 in this chapter). To find the direction of the movement along thex andy axes (corresponding to the Pythonv_x andv_y variables), it is sufficient to use these formulae:

    v_x = -y / (x**2 + y**2)**0.5    v_y = x / (x**2 + y**2)**0.5

If we let one of our particles move, after a certain timet, it will reach another position following a circular path. We can approximate a circular trajectory by dividing the time interval,t, into tiny time steps,dt, where the particle moves in a straight line tangentially to the circle. (Note that higher-order curves could be used rather than straight lines for better accuracy, but we will stick with lines as the simplest approximation.) The final result is just an approximation of a circular motion.

In order to avoid a strong divergence, such as the one illustrated in the following diagram, it is necessary to take very small time steps:

Figure 1.3 – Undesired divergence in particle motion due to large time steps

Figure 1.3 – Undesired divergence in particle motion due to large time steps

In a moreschematic way, we have to carry out the following steps to calculate the particle position at timet:

  1. Calculate the direction of motion (v_x andv_y).
  2. Calculate the displacement (d_x andd_y), which is the product of the time step, angular velocity, and direction of motion.
  3. RepeatSteps 1 and2 enough times to cover the total timet.

The following code snippet shows the fullParticleSimulator implementation:

    class ParticleSimulator:         def __init__(self, particles):             self.particles = particles         def evolve(self, dt):             timestep = 0.00001             nsteps = int(dt/timestep)                  for i in range(nsteps):                for p in self.particles:                    # 1. calculate the direction                     norm = (p.x**2 + p.y**2)**0.5                     v_x = -p.y/norm                     v_y = p.x/norm                     # 2. calculate the displacement                     d_x = timestep * p.ang_vel * v_x                     d_y = timestep * p.ang_vel * v_y                     p.x += d_x                     p.y += d_y                     # 3. repeat for all the time steps

And with that, we havefinished building the foundation of our particle simulator. Next, we will see it in action by visualizing the simulated particles.

Visualizing the simulation

We can use thematplotlib library here to visualize our particles. This library is not includedin the Python standard library, but it can be easily installed using thepip install matplotlib command.

Alternatively, youcan use the Anaconda Python distribution (https://store.continuum.io/cshop/anaconda/), which includesmatplotlib and most of the other third-party packages used in this book. Anaconda is free and is available for Linux, Windows, and Mac.

To make an interactive visualization, we will use thematplotlib.pyplot.plot function to display the particles as points and thematplotlib.animation.FuncAnimation class to animate the evolution of the particles over time.

Thevisualize function takes aParticleSimulator particle instance as an argument and displaysthe trajectory in an animated plot. The steps necessary to display the particle trajectory using thematplotlib tools are outlined here:

  1. Set up the axes and use theplot function to display the particles. Theplot function takes a list ofx andy coordinates.
  2. Write an initialization function,init, and a function,animate, that updates thex andy coordinates using theline.set_data method. Note that ininit, we need to return the line data in the form ofline, due to syntactic reasons.
  3. Create aFuncAnimation instance by passing theinit andanimate functions and theinterval parameters, which specify the update interval, andblit, which improves the update rate of the image.
  4. Run the animation withplt.show(), as illustrated in the following code snippet:
        from matplotlib import pyplot as plt     from matplotlib import animation     def visualize(simulator):         X = [p.x for p in simulator.particles]         Y = [p.y for p in simulator.particles]         fig = plt.figure()         ax = plt.subplot(111, aspect='equal')         line, = ax.plot(X, Y, 'ro')              # Axis limits         plt.xlim(-1, 1)         plt.ylim(-1, 1)         # It will be run when the animation starts         def init():             line.set_data([], [])             return line, # The comma is important!        def animate(i):             # We let the particle evolve for 0.01 time               units             simulator.evolve(0.01)             X = [p.x for p in simulator.particles]             Y = [p.y for p in simulator.particles]             line.set_data(X, Y)             return line,         # Call the animate function each 10 ms         anim = animation.FuncAnimation(fig,          animate,init_func=init,blit=True,            interval=10)         plt.show()

To test this code, we define a small function,test_visualize, that animates a system of three particles rotating in different directions. Note in the following code snippet that the third particle completes a round three times faster than the others:

    def test_visualize():         particles = [                     Particle(0.3, 0.5, 1),                      Particle(0.0, -0.5, -1),                      Particle(-0.1, -0.4, 3)        ]         simulator = ParticleSimulator(particles)         visualize(simulator)     if __name__ == '__main__':         test_visualize()

Thetest_visualize function is helpful to graphically understand the system time evolution. Simplyclose the animation window when you'd like to terminate the program. With this program in hand, in the following section, we will write more test functions to properly verify program correctness and measure performance.

Writing tests and benchmarks

Now that we have a working simulator, we can start measuring our performance and tune up our code sothat the simulator can handle as many particles as possible. As a first step, we will write a test and a benchmark.

We need a test that checks whether the results produced by the simulation are correct or not. Optimizinga program commonly requires employing multiple strategies; as we rewrite our code multiple times, bugs may easily be introduced. A solid test suite ensures that the implementation is correct at every iteration so that we are free to go wild and try different things with the confidence that, if the test suite passes, the code will still work as expected. More specifically, what we are implementing here are called unit tests, which aim to verify the intended logic of the program regardless of the implementation details, which may change during optimization.

Our test will take three particles, simulate them for0.1 time units, and compare the results with those from a reference implementation. A good way to organize your tests is using a separate function for each different aspect (or unit) of your application. Since our current functionality is included in theevolve method, our function will be namedtest_evolve. The following code snippet shows thetest_evolve implementation. Note that, in this case, we compare floating-point numbers up to a certain precision through thefequal function:

    def test_evolve():         particles = [Particle( 0.3,  0.5, +1),                      Particle( 0.0, -0.5, -1),                      Particle(-0.1, -0.4, +3)            ]         simulator = ParticleSimulator(particles)         simulator.evolve(0.1)         p0, p1, p2 = particles         def fequal(a, b, eps=1e-5):             return abs(a - b) < eps         assert fequal(p0.x, 0.210269)         assert fequal(p0.y, 0.543863)         assert fequal(p1.x, -0.099334)         assert fequal(p1.y, -0.490034)         assert fequal(p2.x,  0.191358)         assert fequal(p2.y, -0.365227)     if __name__ == '__main__':         test_evolve()

Theassert statementswill raise an error if the included conditions are not satisfied. Upon running thetest_evolve function, if you notice no error or output printed out, that means all the conditions are met.

A test ensuresthe correctness of our functionality but gives little information about its running time. Abenchmark is a simple and representative use casethat can be run to assess the running time of an application. Benchmarks are very useful to keep score of how fast our program is with each new version that we implement.

We can write a representative benchmark by instantiating a thousandParticle objects with random coordinates and angular velocity and feeding them to aParticleSimulator class. We then let the system evolve for0.1 time units. The code is illustrated in the following snippet:

    from random import uniform     def benchmark():         particles = [          Particle(uniform(-1.0, 1.0), uniform(-1.0, 1.0),             uniform(-1.0, 1.0))           for i in range(1000)]         simulator = ParticleSimulator(particles)         simulator.evolve(0.1)     if __name__ == '__main__':         benchmark()

With the benchmarkprogram implemented, we now need to run it and keep track of the time needed for the benchmark to complete execution, which we will see next. (Note that when you run these tests and benchmarks on your own system, you are likely to see different numbers listed in the text, which is completely normal and dependent on your system configurations and Python version.)

Timing your benchmark

A very simpleway to time a benchmark is through the Unixtime command. Using thetime command, as follows, you can easily measure the execution time of an arbitrary process:

    $ time python simul.pyreal    0m1.051suser    0m1.022ssys     0m0.028s

Thetime command is not available for Windows. To install Unix tools such astime on Windows, you can use thecygwin shell, downloadable from the official website (http://www.cygwin.com/). Alternatively, you can use similar PowerShell commands, such asMeasure-Command (https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/measure-command), to measure execution time.

By default,time displays three metrics, as outlined here:

  • real: The actual time spent running the process from start to finish, as if it were measured by a human with a stopwatch.
  • user: The cumulativetime spent by all thecentral processing units (CPUs) during the computation.
  • sys: The cumulative time spent by all the CPUs during system-related tasks, such as memory allocation.

    Note

    Sometimes,user andsys might be greater thanreal, as multiple processors may work in parallel.

time also offersricher formatting options. For an overview, you can explore its manual (using theman time command). If you want a summary of all the metrics available, you can use the-v option.

The Unixtime command is one of the simplest and most direct ways to benchmark a program. For an accurate measurement, the benchmark should be designed to have a long enough execution time (in the order of seconds) so that the setup and teardown of the process are small compared to the execution time of the application. Theuser metric is suitable as a monitor for the CPU performance, while thereal metric also includes the time spent on other processes while waiting forinput/output (I/O) operations.

Another convenient way to time Python scripts is thetimeit module. This module runs a snippet of code in a loop forn times and measures the total execution time. Then, it repeats the same operationr times (by default, the value ofr is3) and records the time of the best run. Due to this timing scheme,timeit is an appropriate tool to accurately time small statements in isolation.

Thetimeit module can be used as a Python package, from the command line or fromIPython.

IPython is a Python shell design that improves the interactivity of the Python interpreter. It boosts tab completion and many utilities to time, profile, and debug your code. We will use this shell to try out snippets throughout the book. The IPython shell acceptsmagic commands—statements that start with a% symbol—that enhance the shell with special behaviors. Commandsthat start with%% are calledcell magics, which can be appliedon multiline snippets (termed ascells).

IPython is availableon most Linux distributions throughpip and is included in Anaconda. You can use IPython as a regular Python shell (ipython), but it is also available in a Qt-based version (ipython qtconsole) and as a powerful browser-based interface (jupyter notebook).

In IPython andcommand-line interfaces (CLIs), it is possible to specify the number of loops orrepetitions with the-n and-r options. If not specified, they will be automatically inferred bytimeit. When invokingtimeit from the command line, you can also pass some setup code, through the-s option, which will execute before the benchmark. In the following snippet, theIPython command line and Python module version oftimeit are demonstrated:

# IPython Interface $ ipython In [1]: from simul import benchmark In [2]: %timeit benchmark() 1 loops, best of 3: 782 ms per loop # Command Line Interface $ python -m timeit -s 'from simul import benchmark' 'benchmark()'10 loops, best of 3: 826 msec per loop # Python Interface # put this function into the simul.py script import timeitresult = timeit.timeit('benchmark()', setup='from __main__ import benchmark', number=10)# result is the time (in seconds) to run the whole loop result = timeit.repeat('benchmark()',  setup='from __main__ import benchmark', number=10, \    repeat=3) # result is a list containing the time of each repetition (repeat=3 in this case)

Note that whilethe command line and IPython interfaces automatically infer a reasonable number of loopsn, the Python interface requires you to explicitly specify a value through thenumber argument.

Writing better tests and benchmarks with pytest-benchmark

The Unixtime commandis a versatiletool that can be used to assess the runningtime of small programs on a varietyof platforms. For larger Python applications and libraries, a more comprehensive solution that deals with both testing and benchmarking ispytest, in combination with itspytest-benchmark plugin.

In this section, we will write a simple benchmark for our application using thepytest testing framework. For those who are, thepytest documentation, which can be found athttp://doc.pytest.org/en/latest/, is the best resource to learn more about the framework and its uses.

You can installpytest from the console using thepip install pytest command. The benchmarking plugin can be installed, similarly, by issuing thepip install pytest-benchmark command.

A testingframework is a set of tools thatsimplifies writing, executing, anddebugging tests, and provides rich reportsand summaries of the test results. When using thepytest framework, it is recommended to place tests separately from the application code. In the following example, we create atest_simul.py file that contains thetest_evolve function:

    from simul import Particle, ParticleSimulator    def test_evolve():        particles = [                     Particle( 0.3,  0.5, +1),                     Particle( 0.0, -0.5, -1),                     Particle(-0.1, -0.4, +3)          ]        simulator = ParticleSimulator(particles)        simulator.evolve(0.1)            p0, p1, p2 = particles        def fequal(a, b, eps=1e-5):            return abs(a - b) < eps        assert fequal(p0.x, 0.210269)        assert fequal(p0.y, 0.543863)        assert fequal(p1.x, -0.099334)        assert fequal(p1.y, -0.490034)        assert fequal(p2.x,  0.191358)        assert fequal(p2.y, -0.365227)

Thepytest executable can be used from the command line to discover and run tests containedin Python modules. To executea specific test, we can use thepytest path/to/module.py::function_name syntax. To executetest_evolve, we can typethe following command in a console to obtainsimple but informative output:

$ pytest test_simul.py::test_evolveplatform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.32, pluggy-0.4.0rootdir: /home/gabriele/workspace/hiperf/chapter1, inifile: plugins:collected 2 items test_simul.py .=========================== 1 passed in 0.43 seconds ===========================

Once we have a test in place, it is possible for you to execute your test as a benchmark using thepytest-benchmark plugin. If we change ourtest function so that it accepts an argument namedbenchmark, thepytest framework will automatically pass thebenchmark resource as an argument (inpytest terminology, these resources are calledfixtures). Thebenchmark resource can be called by passing the function that we intend to benchmark as the first argument, followed by the additional arguments. In the following snippet, we illustrate the edits necessary to benchmark theParticleSimulator.evolve function:

    from simul import Particle, ParticleSimulator    def test_evolve(benchmark):        # ... previous code        benchmark(simulator.evolve, 0.1)

To runthe benchmark, it is sufficientto rerun thepytest test_simul.py::test_evolve command. Theresulting outputwill contain detailed timing information regarding thetest_evolve function, as shown here:

Figure 1.4 – Output from pytest

Figure 1.4 – Output from pytest

For each test collected,pytest-benchmark will execute thebenchmark function several times and provide a statistic summary of its running time. The preceding output shown is very interesting as it shows how running times vary between runs.

In this example, the benchmark intest_evolve was run34 times (Rounds column), its timings ranged between29 and41milliseconds (ms) (Min andMax), and theAverage andMedian times were fairly similar at about30 ms, which is actually very close to the best timing obtained. This example demonstrates how there can be substantialperformance variabilitybetween runs and that, as opposedto taking timings with one-shottools such astime, it is a good idea to run the program multiple times and record a representative value, such as the minimum or the median.

pytest-benchmark has many more features and options that can be used to take accurate timings and analyze the results. For more information, consult the documentation athttp://pytest-benchmark.readthedocs.io/en/stable/usage.html.

Finding bottlenecks with cProfile

After assessing the correctness and timing of the execution time of the program, we are ready toidentify the parts of the code that need to betuned for performance. We typically aim to identify parts that are small compared to the size of the program.

Two profiling modules are available through the Python standard library, as outlined here:

  • The profile module: This module is written in pure Python and adds significantoverhead to the program execution. Its presence in the standard library is due to its vast platform support and the ease with which it can be extended.
  • The cProfile module: This is the main profiling module, with an interface equivalenttoprofile. It is written in C, has a small overhead, and is suitable as a general-purpose profiler.

ThecProfile module can be used in three different ways, as follows:

  • From the command line
  • As a Python module
  • With IPython

cProfile does not require any change in the source code and can be executed directly on an existing Python script or function. You can usecProfile from the command line in this way:

$ python -m cProfile simul.py

This will print a long output containing several profiling metrics of all of the functions called in the application. You can use the-s option to sort the output by a specific metric. In the following snippet, the output is sorted by thetottime metric, which will be described here:

$ python -m cProfile -s tottime simul.py

The dataproduced bycProfile can be saved in an outputfile by passing the-o option. The format thatcProfile uses is readable by thestats module and other tools. The usage of the-o option is shown here:

$ python -m cProfile -o prof.out simul.py

The usage ofcProfile as a Python module requires invoking thecProfile.run function in the following way:

    from simul import benchmark    import cProfile    cProfile.run("benchmark()")

You can also wrap a section of code between method calls of acProfile.Profile object, as shown here:

    from simul import benchmark    import cProfile    pr = cProfile.Profile()    pr.enable()    benchmark()    pr.disable()    pr.print_stats()

cProfile can alsobe used interactively with IPython. The%prun magiccommand lets you profile an individual function call, as illustrated in the following screenshot:

Figure 1.5 – Using cProfile within IPython

Figure 1.5 – Using cProfile within IPython

ThecProfile output is divided into five columns, as follows:

  • ncalls: The number of times the function was called.
  • tottime: The total time spent in the function without taking into account the calls to other functions.
  • cumtime: The time spent in the function including other function calls.
  • percall: The time spent for a single call of the function—this can be obtained by dividing the total or cumulative time by the number of calls.
  • filename:lineno: The filename and corresponding line numbers. This information is not available when calling C extension modules.

The most important metric istottime, the actual time spent in the function body excluding subcalls, which tells us exactly where the bottleneck is.

Unsurprisingly, the largest portion of time is spent in theevolve function. We can imagine thatthe loop is the section of the code thatneeds performance tuning.cProfile only provides information at the function level and does not tell us which specific statements are responsible for the bottleneck. Fortunately, as we will see in the next section, theline_profiler tool is capable of providing line-by-line information of the time spent in the function.

Analyzing thecProfile text output can be daunting for big programs with a lot of calls and subcalls. Some visual tools aid the task by improving navigation with an interactive, graphical interface.

Graphically analyzing profiling results

KCachegrindis agraphical user interface (GUI) useful for analyzing the profiling output emitted bycProfile.

KCachegrind is availablein the Ubuntu 16.04 official repositories. The Qt port, QCacheGrind, can bedownloaded for Windows fromhttp://sourceforge.net/projects/qcachegrindwin/. Mac users can compile QCacheGrindusing MacPorts (http://www.macports.org/) by following the instructions present in the blog post athttp://blogs.perl.org/users/rurban/2013/04/install-kachegrind-on-macosx-with-ports.html.

KCachegrindcan't directly read the output files produced bycProfile. Luckily, thepyprof2calltree third-party Python module is able to convert thecProfile output file into a format readable by KCachegrind.

You can installpyprof2calltree from thePython Package Index (PyPI) using thepip install pyprof2calltree command.

To best show the KCachegrind features, we will use another example with a more diversified structure. We define a recursive function,factorial, and two other functions that usefactorial, namedtaylor_exp andtaylor_sin. They represent the polynomial coefficients of theTaylor approximations ofexp(x) andsin(x) and are illustrated in the following code snippet:

    def factorial(n):         if n == 0:             return 1.0         else:             return n * factorial(n-1)     def taylor_exp(n):         return [1.0/factorial(i) for i in range(n)]     def taylor_sin(n):         res = []         for i in range(n):             if i % 2 == 1:                res.append((-1)**((i-1)/2)/                   float(factorial(i)))             else:                res.append(0.0)         return res     def benchmark():         taylor_exp(500)         taylor_sin(500)     if __name__ == '__main__':         benchmark()

To access profileinformation, we first need to generate acProfile output file, as follows:

$ python -m cProfile -o prof.out taylor.py

Then, we can convert the output file withpyprof2calltree and launch KCachegrind by running the following code:

$ pyprof2calltree -i prof.out -o prof.calltree$ kcachegrind prof.calltree # or qcachegrind prof.calltree

The output is shown in the following screenshot:

Figure 1.6 – Profiling output generated by pyprof2calltree and displayed by KCachegrind

Figure 1.6 – Profiling output generated by pyprof2calltree and displayed by KCachegrind

The screenshot showsthe KCachegrind UI. On the left, we have an output fairly similar tocProfile. The actual column names are slightly different:Incl. translates to thecProfile module'scumtime value andSelf translates totottime. The values are given in percentages by clicking on theRelative button on the menu bar. By clicking on the column headers, you can sort them by the corresponding property.

On the top right, a click on theCallee Map tab will display a diagram of the function costs. In the diagram shown inFigure 1.6, the time percentage spent by the function is proportional to the area of the rectangle. Rectangles can contain sub-rectangles that represent subcalls to other functions. In this case, we can easily see that there are two rectangles for thefactorial function. The one on the left corresponds to the calls made bytaylor_exp and the one on the right to the calls made bytaylor_sin.

On the bottom right, you can display another diagram, acall graph, by clicking on theCall Graph tab. A call graph is a graphical representation of the calling relationship between the functions; each square represents a function and the arrows imply a calling relationship. For example,taylor_exp callsfactorial500 times, andtaylor_sin callsfactorial250 times. KCachegrind also detects recursive calls:factorial calls itself187250 times.

You can navigate to theCall Graph or theCallee Map tab by double-clicking on the rectangles; the interface will update accordingly, showing that the timing properties are relative to theselected function. For example, double-clicking ontaylor_exp will cause the graph to change, showing only the contribution oftaylor_exp to the total cost.

Gprof2Dot (https://github.com/jrfonseca/gprof2dot) is another popular tool used to producecall graphs. Starting from output files produced by one of the supported profilers, it will generate a.dot diagram representing a call graph.

Profiling line by line with line_profiler

Now that we know which function we have to optimize, we can use theline_profiler module thatprovides information on how time is spent in a line-by-line fashion. This is very useful in situations where it's difficult to determine which statements are costly. Theline_profiler module is a third-party module that is available on PyPI and can be installed by following the instructions athttps://github.com/rkern/line_profiler.

In order to useline_profiler, we need to apply a@profile decorator to the functions we intend to monitor. Note that you don't have to import theprofile function from another module as it gets injected into the global namespace when running thekernprof.py profiling script. To produce profiling output for our program, we need to add the@profile decorator to theevolve function, as follows:

    @profile     def evolve(self, dt):         # code

Thekernprof.py script will produce an output file and print the result of the profiling on the standard output. We should run the script with two options, as follows:

  • -l to use theline_profiler function
  • -v to immediately print the results on screen

The usage ofkernprof.py is illustrated in the following line of code:

$ kernprof.py -l -v simul.py

It is alsopossible to run the profiler in an IPython shell for interactive editing. You should first load theline_profiler extension that will provide thelprun magic command. Using that command, you can avoid adding the@profile decorator, as illustrated in the following screenshot:

Figure 1.7 – Using line_profiler within IPython

Figure 1.7 – Using line_profiler within IPython

The output is quite intuitive and is divided into six columns, as follows:

  • Line #: The number of the line that was run
  • Hits: The number of times that line was run
  • Time: The execution time of the line in microseconds (Time)
  • Per Hit: Time/hits
  • % Time: Fraction of the total time spent executing that line
  • Line Contents: The content of the line

By looking at the% Time column, we can get a pretty good idea of where the time is spent. In thiscase, there are a few statements in thefor loop body with a cost of around 10-20 percent each.

Optimizing our code

Now that we have identified where exactly our application is spending most of its time, we can make some changes and assess the resulting improvement in performance.

There are differentways to tune up our pure Python code. The way that typically produces the most significant results is to improve thealgorithms used. In this case, instead of calculating the velocity and adding small steps, it will be more efficient (and correct, as it is not an approximation) to express the equations of motion in terms of radius,r, and angle,alpha, (instead ofx andy), and then calculate the points on a circle using the following equation:

    x = r * cos(alpha)     y = r * sin(alpha)

Another optimization method lies in minimizing the number of instructions. For example, we can precalculate thetimestep * p.ang_vel factor that doesn't change with time. We can exchange the loop order (first, we iterate on particles, then we iterate on time steps) and put the calculation of the factor outside the loop on the particles.

The line-by-line profiling also showed that even simple assignment operations can take a considerable amount of time. For example, the following statement takes more than 10 percent of the total time:

    v_x = (-p.y)/norm

We can improve the performance of the loop by reducing the number of assignment operations performed. To do that, we can avoid intermediate variables by rewriting the expression into a single, slightly more complex statement (note that the right-hand side gets evaluated completely before being assigned to the variables), as follows:

    p.x, p.y = p.x - t_x_ang*p.y/norm, p.y + t_x_ang *     p.x/norm

This leadsto the following code:

        def evolve_fast(self, dt):             timestep = 0.00001             nsteps = int(dt/timestep)             # Loop order is changed             for p in self.particles:                 t_x_ang = timestep * p.ang_vel                 for i in range(nsteps):                     norm = (p.x**2 + p.y**2)**0.5                     p.x, p.y = (p.x - t_x_ang * p.y/norm,                        p.y + t_x_ang * p.x/norm)

After applying the changes, we should verify that the result is still the same by running our test. We can then compare the execution times using our benchmark, as follows:

$ time python simul.py # Performance Tunedreal    0m0.756suser    0m0.714ssys    0m0.036s$ time python simul.py # Originalreal    0m0.863suser    0m0.831ssys    0m0.028s

As you can see, weobtained only a modest increment in speed by making a pure Python micro-optimization.

Using the dis module

In this section, we will dig into the Python internals to estimate the performance of individual statements. In the CPython interpreter, Python code is first converted to an intermediaterepresentation, thebytecode, and then executed by the Python interpreter.

To inspect howthe code is converted to bytecode, we can use thedis Python module (dis stands fordisassemble). Its usage is really simple; all we need to do is call thedis.dis function on theParticleSimulator.evolve method, like this:

    import dis     from simul import ParticleSimulator     dis.dis(ParticleSimulator.evolve)

This will print, for each line in the function, a list of bytecode instructions. For example, thev_x = (-p.y)/norm statement is expanded in the following set of instructions:

    29           85 LOAD_FAST                5 (p)                  88 LOAD_ATTR                4 (y)                  91 UNARY_NEGATIVE                         92 LOAD_FAST                6 (norm)                  95 BINARY_TRUE_DIVIDE                     96 STORE_FAST               7 (v_x)

LOAD_FAST loads a reference of thep variable onto the stack andLOAD_ATTR loads they attribute of the item present on top of the stack. The other instructions,UNARY_NEGATIVE andBINARY_TRUE_DIVIDE, simply do arithmetic operations on top-of-stack items. Finally, the result is stored inv_x (STORE_FAST).

By analyzing thedis output, we can see that the first version of the loop produces51 bytecode instructions, while the second gets converted into35 instructions.

Thedis modulehelps discover how the statements get converted and serves mainly as an exploration and learning tool of the Python bytecode representation. For a more comprehensive introduction and discussion on the Python bytecode, refer to theFurther reading section at the end of this chapter.

To improve our performance even further, we can keep trying to figure out other approaches to reduce the number of instructions. It's clear, however, that this approach is ultimately limited by the speed of the Python interpreter, and it is probably not the right tool for the job. In the following chapters, we will see how to speed up interpreter-limited calculations by executing fast specialized versions written in a lower-level language (such as C or Fortran).

Profiling memory usage with memory_profiler

In some cases, high memory usage constitutes an issue. For example, if we want to handle ahuge numberof particles, we will incur a memory overhead due to the creation of manyParticle instances.

Thememory_profiler module summarizes, in a way similar toline_profiler, the memory usage of a process.

Thememory_profiler package is also available on PyPI. You should also install thepsutil module (https://github.com/giampaolo/psutil) as an optional dependency that will makememory_profiler considerably faster.

Just as withline_profiler,memory_profiler also requires the instrumentation of the source code by placing a@profile decorator on the function we intend to monitor. In our case, we want to analyze thebenchmark function.

We can slightly changebenchmark to instantiate a considerable amount (100000) ofParticle instances and decrease the simulation time, as follows:

    def benchmark_memory():         particles = [                     Particle(uniform(-1.0, 1.0),                               uniform(-1.0, 1.0),                               uniform(-1.0, 1.0))                       for i in range(100000)            ]         simulator = ParticleSimulator(particles)         simulator.evolve(0.001)

We canusememory_profiler from an IPython shell through the%mprun magic command, as shownin the following screenshot:

Figure 1.8 – Output from memory_profiler

Figure 1.8 – Output from memory_profiler

It ispossible to runmemory_profiler from the shell using themprof run command after adding the@profile decorator.

FromtheIncrement column, we can see that 100,000Particle objects take23.7 MiB of memory.

1mebibyte (MiB) is equivalent to 1,048,576 bytes. It is different from 1megabyte (MB), which is equivalent to 1,000,000 bytes.

We can use__slots__ on theParticle class to reduce its memory footprint. This feature saves some memory by avoiding storing the variables of the instance in an internal dictionary. This strategy, however, has a small limitation—it prevents the addition of attributes other than the ones specified in__slots__. You can see this feature in use in the following code snippet:

    class Particle:        __slots__ = ('x', 'y', 'ang_vel')         def __init__(self, x, y, ang_vel):             self.x = x             self.y = y             self.ang_vel = ang_vel

We cannow rerun ourbenchmark to assess the change in memory consumption. The result is displayed in the following screenshot:

Figure 1.9 – Improvement in memory consumption

Figure 1.9 – Improvement in memory consumption

By rewriting theParticle class using__slots__, we can save about 10 MiB of memory.

Summary

In this chapter, we introduced the basic principles of optimization and applied those principles to a test application. When optimizing an application, the first thing to do is test and identify the bottlenecks in the application. We saw how to write and time a benchmark using thetime Unix command, the Pythontimeit module, and the full-fledgedpytest-benchmark package. We learned how to profile our application usingcProfile,line_profiler, andmemory_profiler, and how to analyze and navigate the profiling data graphically with KCachegrind.

Speed is undoubtedly an important component of any modern software. The techniques we have learned in this chapter will allow you to systematically tackle the problem of making your Python programs more efficient from different angles. Further, we have seen that these tasks can take advantage of Python built-in/native packages and do not require any special external tools.

In the next chapter, we will explore how to improve performance using algorithms and data structures available in the Python standard library. We will cover scaling and sample usage of several data structures, and learn techniques such as caching and memorization. We will also introduce Big O notation, which is a common computer science tool to analyze the running time of algorithms and data structures.

Questions

  1. Arrange the following three items in order of importance when building a software application: correctness (the program does what it is supposed to do), efficiency (the program is optimized in speed and memory management), and functionality (the program runs).
  2. How couldassert statements be used in Python to check for the correctness of a program?
  3. What is a benchmark in the context of optimizing a software program?
  4. How couldtimeit magic commands be used in Python to estimate the speed of a piece of code?
  5. List three different types of information that are recorded and returned bycProfile (included as output columns) in the context of profiling a program.
  6. On a high level, what is the role of thedis module in optimization?
  7. In theexercise.py file, we write a simple function,close(), that checks whether a pair of particles are close to each other (with 1e-5 tolerance). Inbenchmark(), we randomly initialize two particles and callclose() after running the simulation. Make a guess of what takes most of the execution time inclose(), and profile the function viabenchmark() usingcProfile; does the result confirm your guess?

Further reading

Left arrow icon

Page1 of 12

Right arrow icon
Download code iconDownload Code

Key benefits

  • Benchmark, profile, and accelerate Python programs using optimization tools
  • Scale applications to multiple processors with concurrent programming
  • Make applications robust and reusable using effective design patterns

Description

Python's powerful capabilities for implementing robust and efficient programs make it one of the most sought-after programming languages.In this book, you'll explore the tools that allow you to improve performance and take your Python programs to the next level.This book starts by examining the built-in as well as external libraries that streamline tasks in the development cycle, such as benchmarking, profiling, and optimizing. You'll then get to grips with using specialized tools such as dedicated libraries and compilers to increase your performance at number-crunching tasks, including training machine learning models.The book covers concurrency, a major solution to making programs more efficient and scalable, and various concurrent programming techniques such as multithreading, multiprocessing, and asynchronous programming.You'll also understand the common problems that cause undesirable behavior in concurrent programs.Finally, you'll work with a wide range of design patterns, including creational, structural, and behavioral patterns that enable you to tackle complex design and architecture challenges, making your programs more robust and maintainable.By the end of the book, you'll be exposed to a wide range of advanced functionalities in Python and be equipped with the practical knowledge needed to apply them to your use cases.

Who is this book for?

This book is for intermediate to experienced Python programmers who are looking to scale up their applications in a systematic and robust manner. Programmers from a range of backgrounds will find this book useful, including software engineers, scientific programmers, and software architects.

What you will learn

  • Write efficient numerical code with NumPy, pandas, and Xarray
  • Use Cython and Numba to achieve native performance
  • Find bottlenecks in your Python code using profilers
  • Optimize your machine learning models with JAX
  • Implement multithreaded, multiprocessing, and asynchronous programs
  • Solve common problems in concurrent programming, such as deadlocks
  • Tackle architecture challenges with design patterns

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date :Mar 25, 2022
Length:606 pages
Edition :2nd
Language :English
ISBN-13 :9781801817776
Vendor :
Google
Category :
Tools :

What do you get with eBook?

Product feature iconInstant access to your Digital eBook purchase
Product feature icon Download this book inEPUB andPDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature iconDRM FREE - Read whenever, wherever and however you want
Product feature iconAI Assistant (beta) to help accelerate your learning
OR

Contact Details

Modal Close icon
Payment Processing...
tickCompleted

Billing Address

Product Details

Publication date :Mar 25, 2022
Length:606 pages
Edition :2nd
Language :English
ISBN-13 :9781801817776
Vendor :
Google
Category :
Concepts :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
₹800billed monthly
Feature tick iconUnlimited access to Packt's library of 7,000+ practical books and videos
Feature tick iconConstantly refreshed with 50+ new titles a month
Feature tick iconExclusive Early access to books as they're written
Feature tick iconSolve problems while you work with advanced search and reference features
Feature tick iconOffline reading on the mobile app
Feature tick iconSimple pricing, no contract
₹4500billed annually
Feature tick iconUnlimited access to Packt's library of 7,000+ practical books and videos
Feature tick iconConstantly refreshed with 50+ new titles a month
Feature tick iconExclusive Early access to books as they're written
Feature tick iconSolve problems while you work with advanced search and reference features
Feature tick iconOffline reading on the mobile app
Feature tick iconChoose a DRM-free eBook or Video every month to keep
Feature tick iconPLUS own as many other DRM-free eBooks or Videos as you like for just ₹400 each
Feature tick iconExclusive print discounts
₹5000billed in 18 months
Feature tick iconUnlimited access to Packt's library of 7,000+ practical books and videos
Feature tick iconConstantly refreshed with 50+ new titles a month
Feature tick iconExclusive Early access to books as they're written
Feature tick iconSolve problems while you work with advanced search and reference features
Feature tick iconOffline reading on the mobile app
Feature tick iconChoose a DRM-free eBook or Video every month to keep
Feature tick iconPLUS own as many other DRM-free eBooks or Videos as you like for just ₹400 each
Feature tick iconExclusive print discounts

Frequently bought together


Advanced Python Programming
Advanced Python Programming
Read more
Mar 2022606 pages
Full star icon4.6 (14)
eBook
eBook
₹799.99₹2800.99
₹3500.99
Learn Python Programming, 3rd edition
Learn Python Programming, 3rd edition
Read more
Oct 2021554 pages
Full star icon4.2 (35)
eBook
eBook
₹799.99₹3220.99
₹3500.99
Mastering Python 2E
Mastering Python 2E
Read more
May 2022710 pages
Full star icon4.6 (65)
eBook
eBook
₹799.99₹2978.99
₹3723.99
Stars icon
Total10,725.97
Advanced Python Programming
₹3500.99
Learn Python Programming, 3rd edition
₹3500.99
Mastering Python 2E
₹3723.99
Total10,725.97Stars icon

Table of Contents

31 Chapters
Section 1: Python-Native and Specialized OptimizationChevron down iconChevron up icon
Section 1: Python-Native and Specialized Optimization
Chapter 1: Benchmarking and ProfilingChevron down iconChevron up icon
Chapter 1: Benchmarking and Profiling
Technical requirements
Designing your application
Writing tests and benchmarks
Writing better tests and benchmarks with pytest-benchmark
Finding bottlenecks with cProfile
Optimizing our code
Using the dis module
Profiling memory usage with memory_profiler
Summary
Questions
Further reading
Chapter 2: Pure Python OptimizationsChevron down iconChevron up icon
Chapter 2: Pure Python Optimizations
Technical requirements
Using the right algorithms and data structures
Improved efficiency with caching and memoization
Efficient iteration with comprehensions and generators
Summary
Questions
Further reading
Chapter 3: Fast Array Operations with NumPy, Pandas, and XarrayChevron down iconChevron up icon
Chapter 3: Fast Array Operations with NumPy, Pandas, and Xarray
Technical requirement
Getting started with NumPy
Rewriting the particle simulator in NumPy
Reaching optimal performance with numexpr
Working with database-style data with pandas
High-performance labeled data with xarray
Summary
Questions
Further reading
Chapter 4: C Performance with CythonChevron down iconChevron up icon
Chapter 4: C Performance with Cython
Technical requirements
Compiling Cython extensions
Adding static types
Sharing declarations
Working with arrays
Using a particle simulator in Cython
Profiling Cython
Using Cython with Jupyter
Summary
Questions
Chapter 5: Exploring CompilersChevron down iconChevron up icon
Chapter 5: Exploring Compilers
Technical requirements
Getting started with Numba
The PyPy project
Other interesting projects
Summary
Questions
Further reading
Chapter 6: Automatic Differentiation and Accelerated Linear Algebra for Machine LearningChevron down iconChevron up icon
Chapter 6: Automatic Differentiation and Accelerated Linear Algebra for Machine Learning
A crash course in machine learning
Getting JAX up and running
Automatic differentiation for loss minimization
Just-In-Time compilation for improved efficiency
Automatic vectorization for efficient kernels
Summary
Questions
Further reading
Section 2: Concurrency and ParallelismChevron down iconChevron up icon
Section 2: Concurrency and Parallelism
Chapter 7: Implementing ConcurrencyChevron down iconChevron up icon
Chapter 7: Implementing Concurrency
Technical requirements
Asynchronous programming
The asyncio framework
Reactive programming
Summary
Questions
Further reading
Chapter 8: Parallel ProcessingChevron down iconChevron up icon
Chapter 8: Parallel Processing
Technical requirements
Introduction to parallel programming
Using multiple processes
Parallel Cython with OpenMP
Automatic parallelism
Summary
Questions
Chapter 9: Concurrent Web RequestsChevron down iconChevron up icon
Chapter 9: Concurrent Web Requests
The basics of web requests
The requests module
Concurrent web requests
The problem with timeouts
Good practices in making web requests
Summary
Questions
Further reading
Chapter 10: Concurrent Image ProcessingChevron down iconChevron up icon
Chapter 10: Concurrent Image Processing
Technical requirements
Image processing fundamentals
Applying concurrency to image processing
Good concurrent image processing practices
Summary
Questions
Further reading
Chapter 11: Building Communication Channels with asyncioChevron down iconChevron up icon
Chapter 11: Building Communication Channels with asyncio
Technical requirements
The ecosystem of communication channels
Getting started with Python and Telnet
Client-side communication with aiohttp
Summary
Questions
Further reading
Chapter 12: DeadlocksChevron down iconChevron up icon
Chapter 12: Deadlocks
Technical requirements
The concept of deadlocks
Approaches to deadlock situations
The concept of livelocks
Summary
Questions
Further reading
Chapter 13: StarvationChevron down iconChevron up icon
Chapter 13: Starvation
Technical requirements
Understanding starvation
Approaching the readers-writers problem
Solutions to starvation
Summary
Questions
Further reading
Chapter 14: Race ConditionsChevron down iconChevron up icon
Chapter 14: Race Conditions
Technical requirements
The concept of race conditions
Simulating race conditions in Python
Locks as a solution to race conditions
Race conditions in real life
Summary
Questions
Further reading
Chapter 15: The Global Interpreter LockChevron down iconChevron up icon
Chapter 15: The Global Interpreter Lock
Technical requirements
Introducing the GIL
The potential removal of the GIL from Python
Working with the GIL
Summary
Questions
Further reading
Section 3: Design Patterns in PythonChevron down iconChevron up icon
Section 3: Design Patterns in Python
Chapter 16: The Factory PatternChevron down iconChevron up icon
Chapter 16: The Factory Pattern
Technical requirements
Understanding design patterns
Implementing the factory method
Applying the abstract factory
Summary
Questions
Chapter 17: The Builder PatternChevron down iconChevron up icon
Chapter 17: The Builder Pattern
Technical requirements
Understanding the builder pattern
Real-world examples
Use cases
Implementing an ordering application
Summary
Questions
Chapter 18: Other Creational PatternsChevron down iconChevron up icon
Chapter 18: Other Creational Patterns
Technical requirements
Implementing the prototype pattern
Implementing the singleton pattern
Summary
Questions
Further reading
Chapter 19: The Adapter PatternChevron down iconChevron up icon
Chapter 19: The Adapter Pattern
Technical requirements
Understanding the adapter pattern
Real-world examples
Use cases
Implementation
Summary
Chapter 20: The Decorator PatternChevron down iconChevron up icon
Chapter 20: The Decorator Pattern
Technical requirements
Introducing the decorator pattern
Real-world examples
Use cases
Implementation
Summary
Questions
Chapter 21: The Bridge PatternChevron down iconChevron up icon
Chapter 21: The Bridge Pattern
Technical requirements
Real-world examples
Use cases
Implementation
Summary
Questions
Chapter 22: The Façade PatternChevron down iconChevron up icon
Chapter 22: The Façade Pattern
Technical requirements
Understanding the façade pattern
Real-world examples
Use cases
Implementation
Summary
Questions
Further reading
Chapter 23: Other Structural PatternsChevron down iconChevron up icon
Chapter 23: Other Structural Patterns
Technical requirements
Implementing the flyweight pattern
Implementing the model-view-controller pattern
Applying the proxy pattern
Summary
Questions
Chapter 24: The Chain of Responsibility PatternChevron down iconChevron up icon
Chapter 24: The Chain of Responsibility Pattern
Technical requirements
Understanding the Chain of Responsibility pattern
Real-world examples
Use cases
Implementation
Summary
Questions
Chapter 25: The Command PatternChevron down iconChevron up icon
Chapter 25: The Command Pattern
Technical requirements
Understanding the command pattern
Real-world examples
Use cases
Implementation
Summary
Questions
Chapter 26: The Observer PatternChevron down iconChevron up icon
Chapter 26: The Observer Pattern
Technical requirements
Understanding the observer pattern
Real-world examples
Use cases
Implementation
Summary
Questions
AssessmentsChevron down iconChevron up icon
Chapter 1
Chapter 2
Chapter 3
Chapter 4
Chapter 5
Chapter 6
Chapter 7
Chapter 8
Chapter 9
Chapter 10
Chapter 11
Chapter 12
Chapter 13
Chapter 14
Chapter 15
Chapter 16
Chapter 17
Chapter 18
Chapter 20
Chapter 21
Chapter 22
Chapter 23
Chapter 24
Chapter 25
Chapter 26
Why subscribe?
Other Books You May EnjoyChevron down iconChevron up icon
Other Books You May Enjoy
Packt is searching for authors like you
Share Your Thoughts

Recommendations for you

Left arrow icon
Debunking C++ Myths
Debunking C++ Myths
Read more
Dec 2024226 pages
eBook
eBook
₹799.99₹2382.99
₹2978.99
Go Recipes for Developers
Go Recipes for Developers
Read more
Dec 2024350 pages
eBook
eBook
₹799.99₹2382.99
₹2978.99
50 Algorithms Every Programmer Should Know
50 Algorithms Every Programmer Should Know
Read more
Sep 2023538 pages
Full star icon4.5 (68)
eBook
eBook
₹799.99₹2978.99
₹3723.99
Asynchronous Programming with C++
Asynchronous Programming with C++
Read more
Nov 2024424 pages
Full star icon5 (1)
eBook
eBook
₹799.99₹2502.99
₹3127.99
Modern CMake for C++
Modern CMake for C++
Read more
May 2024502 pages
Full star icon4.7 (12)
eBook
eBook
₹799.99₹2978.99
₹3723.99
Learn Python Programming
Learn Python Programming
Read more
Nov 2024616 pages
Full star icon5 (1)
eBook
eBook
₹799.99₹2382.99
₹2978.99
Learn to Code with Rust
Learn to Code with Rust
Read more
Nov 202457hrs 40mins
Video
Video
₹5585.99
Modern Python Cookbook
Modern Python Cookbook
Read more
Jul 2024818 pages
Full star icon4.9 (21)
eBook
eBook
₹799.99₹3276.99
₹4096.99
Right arrow icon

Customer reviews

Top Reviews
Rating distribution
Full star iconFull star iconFull star iconFull star iconHalf star icon4.6
(14 Ratings)
5 star71.4%
4 star21.4%
3 star7.1%
2 star0%
1 star0%
Filter icon Filter
Top Reviews

Filter reviews by




Krishnan RaghavanMay 23, 2022
Full star iconFull star iconFull star iconFull star iconFull star icon5
Python is a programming language that is mostly used for fast prototyping and software development both by beginners for its easy-to-learn syntax as well as by experienced programmers. It's not a language preferred when it comes to scaling or speed. Most programmers prefer other programming languages for this. The author of this book has tried to show that this is not really necessary and even Python has enough tools and support for optimizing and scaling.This book is best utilized by intermediate to expert programmers who are looking to scale up their applications and make them more robust.What I learnt from this book:1. How to identify sections of the code that is slowing down and increasing the execution time and how to optimize and increase the performance of the code using data structures, algorithms and third-party tools efficiently.2. Fast Array Operations with NumPy, Pandas and Xarray to implement fast numerical algorithms.3. Improve performance with Cython and other compilers like Numba Framework that can be used to compile Python code.4. Tools and Libraries that help implement parallelism and concurrency for web requests, Image processing tasks, deadlock, and Race Conditions kinds of situations.5. Factory Design Patterns and benefits of using Factory design patterns instead of direct object instantiation.6. How to implement Concurrency and Parallel Programming on multi-core processors and GPUs. Very useful for data science projects.At the end of each chapter, the author has provided a summary that helps in revising the chapter and questions that will test your knowledge about the chapter. Wherever applicable, additional material for reading is suggested.This book has helped me understand topics of which I was not aware previously. Kudos to Quan Nguyen for the effort in bringing out this excellent book. Thank you very much, Quan Nguyen.
Amazon Verified reviewAmazon
Ryan ZurrinJun 10, 2022
Full star iconFull star iconFull star iconFull star iconFull star icon5
The media could not be loaded. Advanced Python Programming 2nd edition by Quan Nguyen. Over 500 pages of pythonic knowledge that I consider a must know for anyone using python programming professionally. As a fulltime student working as a researcher, researching Breast Cancer detection using machine learning, I use python daily and this book has been so helpful for me in developing and strengthening areas I was previously lacking.Another one of the things I loved about this book is the example they use throughout the book, a simple particle simulator. If you love physics as I do, you will fall in love with this example, and how it grows throughout the book, getting better and better as we learn how to use more powerful techniques to achieve the best performance from whatever we are building.Advanced Python Programming 2nd Edition also covers topics like Machine Learning, just the basics, but it is a good start. It gets into how to use Concurrency and parallel processing, what the differences are between them, and what some of the common mistakes us beginners usually face when first starting out in these tough areas of python programming. This book is truly a toolbox of techniques for us to use, which can help us to become masters of this unique and diverse programming language.There is a whole section on Design Patterns which was recently so helpful for me in my research. I had to build a singleton class and had no idea what that even was, and I was able to look it up in this book and learn exactly what I needed to do to implement one on my own. Other design patterns covered are things like the Factory Pattern, the Builder Pattern, Creational Patterns – for which the Singleton was a part of, the Adapter Pattern, the Decorator Pattern, Bridge Pattern and more. It really gets into the nitty gritty of how to properly program in python.So, if you are programming in python professionally already or just looking for a book to boost up what you already know this book is for you. It does not get into the basics of python so it starts out assuming you already have that experience so if you never programmed in python before you may want to start someplace else before trying this book, but I think it is a great book for anyone who plans to use python on a regular basis.Packt books has done it again and brought us another great technical book by another great author, Quan Nguyen who does wonders in this book. Advanced Python Programming 2nd edition is an amazing book so I’d say pick it up if you can, it will not disappoint.
Amazon Verified reviewAmazon
Jaime Sierra Silva (Consignment)Nov 24, 2022
Full star iconFull star iconFull star iconFull star iconFull star icon5
Python is a very versatile language, in general, one thing is to learn a language and another thing is to use it in the most optimal way, so that the software that is developed is of a performance for its users and the structure in which it is located.In "Advanced Python Programming", the author delves into techniques and practices to optimize programs written in Python, so that it uses optimally the resources at its disposal and fulfills its objectives in the best way. The book takes us through the different aspects to consider to improve our codes, the only goal is to be a better Python developer.
Amazon Verified reviewAmazon
jmlMay 13, 2022
Full star iconFull star iconFull star iconFull star iconFull star icon5
Advanced Python Programming, Second Edition offers a variety of in-depth coverage in its roughly 550 pages. The book starts off with optimization techniques, useful to all Python programmers but especially those focusing on mathematical specialties (NumPy, Pandas, and Xarray). There’s also a neat introduction to machine learning, which leads smoothly into a treatment of parallel and threaded processing. Deadlocks, thread starvation, and the global interpreter lock are explained in a context useful to Python professionals. Finally, several in-depth chapters are devoted to the care and feeding of various design patterns and factories. If you're not comfortable with those functions when you start the book, you probably will be once you finish it. The author, Quan Nguyen, has done a solid job of presenting the material without overwhelming the reader, using code examples, projects, and diagrams where appropriate. Chapters are well-paced making for a very readable book. As the title indicates, this is not a beginner’s guide or a Python tutorial, but experienced programmers will definitely pick up some new knowledge from a thorough reading.
Amazon Verified reviewAmazon
Jaelyn JensenMay 20, 2022
Full star iconFull star iconFull star iconFull star iconFull star icon5
First impression was "Even though it's pretty long (~550 pages), this will be an easy read, because I already have substantial experience with Design Patterns in C++."Well, it was a lot more than just a Design Patterns in Python3 book. I wasn't very far into the book when my hubris became embarrassingly obvious. The author didn't even start in on the Design Patterns stuff until nearly 2/3rds of the way through the book. Well, that part was a comparably easy read, partially because using the GoF patterns in Python is a little easier than in C++. Well, mostly, anyway. Python3 makes using most of the GoF patterns pretty straightforward.The first two-thirds of the book were more challenging (and informative) than I expected. The author takes a deep dive into various ways to optimize and improve your code. Of course, he started off with the observation that the choice of algorithm totally dominates that process. But I certainly learned a lot about Python3 (and various library) optimizations.I got introduced to a lot of different things in Python3 that I didn't know existed, and got to review some things I had not encountered in a long time. In a way, learning Python is a lot like learning Java, in the sense that the syntax of the language is pretty easy to understand. The problem is that learning the proper syntax rules puts you at about 5% of the way to being a proficient programmer. Learning the "Pythonic" way of doing stuff (like making appropriate use of things like tuples and dictionaries) gets you to maybe 15%. Learning a huge body of existing libraries gets you to about 80%, after which incremental gains get more challenging.I think that this book can get you to almost 100% (actually, 100% might not really be achievable in any discipline -- or maybe the field just continues to expand) of the way to production programming. Well, this book and a few years of experience. If you already have a bit of Python3 experience, then this book is a great follow-on to get your Python3 chops to the next level.I liked the way the assessment questions were used, and I appreciated the coverage of the assessment answers at the end. The assessments were well-done.I can think of only two things to suggest for improvement. The first would be to make this into 3 books instead of one huge tome. That might have made it somewhat less overwhelming The second would be to provide an overview of how to use the various help facilities in Python. Although by the time you really need this book, you probably already have that 2nd part figured out.This book will be one that I return to often for reference.
Amazon Verified reviewAmazon
  • Arrow left icon Previous
  • 1
  • 2
  • 3
  • Arrow right icon Next

People who bought this also bought

Left arrow icon
50 Algorithms Every Programmer Should Know
50 Algorithms Every Programmer Should Know
Read more
Sep 2023538 pages
Full star icon4.5 (68)
eBook
eBook
₹799.99₹2978.99
₹3723.99
Event-Driven Architecture in Golang
Event-Driven Architecture in Golang
Read more
Nov 2022384 pages
Full star icon4.9 (11)
eBook
eBook
₹799.99₹2978.99
₹3723.99
The Python Workshop Second Edition
The Python Workshop Second Edition
Read more
Nov 2022600 pages
Full star icon4.6 (22)
eBook
eBook
₹799.99₹3562.99
₹3872.99
Template Metaprogramming with C++
Template Metaprogramming with C++
Read more
Aug 2022480 pages
Full star icon4.6 (14)
eBook
eBook
₹799.99₹3220.99
₹3500.99
Domain-Driven Design with Golang
Domain-Driven Design with Golang
Read more
Dec 2022204 pages
Full star icon4.4 (19)
eBook
eBook
₹799.99₹2680.99
₹3351.99
Right arrow icon

About the author

Profile icon Quan Nguyen
Quan Nguyen
LinkedIn iconGithub icon
Quan Nguyen, the author of the first edition of this book, is a Python programmer with a strong passion for machine learning. He holds a dual degree in mathematics and computer science, with a minor in philosophy, earned from DePauw University. Quan is deeply involved in the Python community and has authored multiple Python books, contributing to the Python Software Foundation and regularly sharing insights on DataScience portal. He is currently pursuing a Ph.D. in computer science at Washington University in St. Louis.
Read more
See other products by Quan Nguyen
Getfree access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook?Chevron down iconChevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website?Chevron down iconChevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook?Chevron down iconChevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support?Chevron down iconChevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks?Chevron down iconChevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook?Chevron down iconChevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.


[8]ページ先頭

©2009-2025 Movatter.jp