 Good morning. Thank you. That's a Pleasant welcome. Thank you very much for coming to my talk. I am going to talk about perform Python now I'm slightly disorganized and I forgot to bring batteries for my clicky thing. So I'll be wandering back and forth bear with me What do I mean by perform Python? I'd like us to think about writing good fast Python code now there are three words in there good fast and Python and to my mind they kind of have equal significance So let's talk about good code first now good code It's complicated as a concept We all know good code when we see it right There's there's all sorts of measurements you can apply and there's academic literature about what is good code and what's not good code as a working definition, I'll just say it's called that we can easily read and understand The next thing is fast code now I love Python. I've been programming in Python for oh, I don't know since about version 1.6 And there are lots of things I love about Python But I don't write Python because it's fast, right? but it is fast enough for pretty much everything I need to do and with a few tricks It is actually fast enough for everything I do at the moment Now I have to kind of limit that slightly my domain is mainly financial simulations, so You know I do floating point of arithmetic all day long and for that as fast enough if your domain is web services IO huge databases you might not get that much out of this talk, but bear with me. Hopefully you'll enjoy it and the last word We want to talk about is oops Python We can you know, there's the old joke about a good pro, you know real program I can write for trying in any language and as A card carrying C++ programmer. I can certainly write C++ or Java in Python Particularly when people write Java and Python with lots of abstract interfaces and abstract methods it kind of irritates me But we can so I want us to focus also on writing Python code for a number of reasons One is because it's it's actually much nicer to read and write then C++ and Python or Java and Python, but also it's faster. So let's move on with the slide that's gone out of sink Before we talk about speed, let's reconsider the famous quote from nooth Basically 97% of the time we shouldn't worry about small inefficiencies The 3% of the time that we should worry about them. It really matters. So bear that in mind. I mean One of the things I'm trying to get across to people is that My slides are out of order. Never mind That computers are cheap programmers are expensive, right? You know every now and then you hear about skills shortages shortage of programmers. Have you ever heard about a shorter of computers? Recently. No, okay. So let's move on What I mean by pythonic you've Has anybody ever done this read this the Zen of Python quick show hands Excellent, most of you have those of you haven't just type import this at the Python prompt you get the whole lot of this And I like the Top three kind of making make the most sense to me, right beautiful is better than ugly who could argue with that Explicit is better than implicit. I think that's also very important And simple is always better than complex. I have to always tell myself I'm a bear of little brain and complex code bothers me Who was it that said the You know debugging your code is 10 times more difficult than writing it So if the code you write is as complex as you can write it You have no chance of understanding of being able to debug it So that's always something I have to bear in mind Okay, so a couple of themes I'll come through here Pythonic right so by my my working definition of Pythonic and I'm happy to have a philosophical discussion about this Over coffee later is just clean and readable I will talk a little about profiling I Don't believe the quote about that you can't manage what you can't measure. I think from a people management perspective. That's bullshit From a programming perspective, it is absolutely correct, right? There's no point Making any assumptions or building a hypothesis about your code unless you can measure what your code is doing Once you have measured it of course the key things to speed things up is to do less The fastest most reliable code as somebody much more intelligent I pointed out is code that you don't write right if code isn't there it Executes instantaneously. It has no bugs. So whenever you can do less Or jump ahead and cheat and get somebody else to do it for you. That is a win in programming The other two topics that come up a little bit later is vectorizing and parallelizing Slightly interchangeable vectorizing from a from my perspective over with somebody who writes in relatively slow language and Like his code to work quickly basically means that when we pass stuff off to when we pass data off to Faster language or a faster subsystem. We do it in one go and operate on the whole batch of data To basically pay the overhead off of the of the call only once And obviously parallelizing means using as many cores or computers as we can So let's go back to Python performs Now, you know on on the interwebs and all that you constantly hear about this Python is slow Compared to X Y Z. What does it mean? you know, I Don't think that's you know, Python being being slow isn't really an issue. The question is this Python too slow. I Don't think it is for any anything that I do and I do a fair bit of you know perform sensitive stuff in that domain and You know, we we have a couple hundred thousand lines of library code And most of that is not perform sensitive at all There are a few hot spots where we do worry about performs But once you worry a little bit about them and deal with them properly It actually turns out that Python is fast enough So let's look at some code Hopefully that's big enough for the people in the back to see So this is this is kind of you know, Python 101 code This is the kind of code. I would have would have written in 1999 when I started Python programming and You know, it's it's simple. It's clear. It's readable it works You know, all three of those are Pretty pretty good attributes for a little piece of code to have you know as a starting point is it fast Well, let's write a little Gadget to measure it. This is probably not as similar to I Python time it How many I Python users in the room? Cool. Why don't you bite up like those of you who don't use I Python? Why not? I mean, I don't use the notebooks myself, but as a command line, you can't beat it So let's look at this code, right? So if I run this and Little bit of test code there I'm gonna run 10 add up 10 million random numbers and it comes back in just over half a second That seems pretty damn quick to me You know, I Hate to play the old man card here But you know the computers I started programming on couldn't even handle 10 million random numbers much less add them up in half a second So that's not too bad. So why are people still worried about Python performance? Well, they're worried about Python performance compared to C++ or C, right? So let's look at the same program in see who his Nobody nobody hates C. Okay, good. I'll take my C++ jokes out later on. Okay So this is very similar But if we time it we'll find out that it is About 40 times faster than our Python program Which is a bit irritating You know just for bragging rights over the coffee if you talk to a C++ program or if you really have something very time critical So let's look at this code again this code is actually Pretty much exactly the same as the C code Now I Think we can make it faster by making it better. So if we just go To slightly more modern more Pythonic style and instead of, you know, accent using random access iterated Stop again instead of using random access and using a C-style for loop if we just use a Proper Python for loop and iterate over a collection is actually I think a little bit faster. Let's have a look Oh, yeah, the other so to me. This is kind of the the canonical perfect Python function to do a sum You know the current fashion is for going all functional programming, so I did write a functional version of it Not desperately keen on that myself, but you know as a follower of fashion. I had to put it in so Does does Changing it changing a code to make it more Pythonic actually make it faster Yes, it does. So if you look at the the second line down, you know, we've got a 100% well 50% whichever way around you measure it Performance improvement by making a code a little bit simpler a little bit cleaner a little bit tidier Which is great, but it's still about 20 times slower than C++ okay, so Hmm, so let's Think about what else we have in our arsenal and obviously you all know Python, so you know that we have a sum Function built into Python And we should just use that instead of reinventing the wheel badly and That takes us to pretty much the same ballpark as C++ it's still a little bit slower But you know at least we're in the same town now, right? So I think you know this kind of shows that actually if you write Python properly And know the language and use the facilities in the language You're gonna get something that's you know You know three or four times slower than C++ But that isn't you know an order of magnitude or two orders of magnitude so it's you know for most things It's probably not something you have to worry about But we have a few more tricks up our sleeve so This is what I do at work. I Basically use numpy And this is this is what I kind of mean by cheating right so I don't want to write C++ code all day Why not because you know writing optimized numerically efficient C++ code It's hard work. I'd much rather get somebody else to do it for me and the nice people at numpy have done that So this is really good now. Let's look at the performance of that We're cheating slightly because we're we're converting from a Python List to an umpy array because it's more efficient data structure But glossing over that we're actually faster than C++ That surprised me a little bit last night when I put this slide together But you know it's so this is kind of what I you know what we do all day It's not very surprising because we're You know we're comparing C code written by somebody who hasn't really written C for a living for 20 years To some of the best C++ programs in the world and they're faster than I am. That's great so There's other things we can do though because sometimes numpy It's a little bit awkward to use if you're not using You know if you're not doing Basically matrix arithmetic So we can cheat again in a different way Oh, we've vectorized we've gone pythonic. That's cheap and This is the slide from before we see Python If we use pi pi we get With that with any of the version of the code. We're just as fast as a C++ code So, you know if you have a performance problem look at some of the new jits out there Pi pi is great You know, we didn't even have to worry about Rewriting anything. I mean, I still think you should write the more pythonic version of the code But the performance gain you can get from cheating with pi pi is fantastic. So let's look at that Now there's something different about this slide from the previous slide And that's the fact that we're missing the numpy version now pi pi num pi haven't I Have had problems integrating in the past They're slowly getting better that I mean I you can actually now install numpy and pi pi together And it works. I just didn't have a chance to try it on my laptop Before coming to do these slides Yeah the kind of other Thing you might want to look at if you want to look at a jit is number number, which is gives you a number of Deployment opportunities to to use GPUs if you have the kind of problem that fits the GPU Now in my experience, that's one of those situations where if your problems fits the hardware architecture It's fantastic But it has to be a pretty close fit of your problem to the hardware architecture. So your mileage may vary Let's move on That was a cheat and remember this now It's interesting this quote has probably been stolen more than any other quote. I've run across from a quote checker So I've seen it attributed to Picasso Tennyson and Jobs I Don't really care If it's good enough for any of them, it's good enough for me. So I Think the key one of the real key things to getting your Python code far as is to actually, you know see what other workers out there already check what you can take from other people and Use it and improve it moving on profiling and doing this so Let's start with some really not a naughty code So these are anagrams Yeah, then they used to be something that people did before the internet wasn't invented to keep themselves amused at night But they're they're really tedious to work out by hand Quite fun sometimes with political developments But anyway, so let's let's see if we can get a computer program to work them out So what do we do here? We? First of all read the list of dictionaries So we have a list of all the words we're going to look at and then we have a very simple kind of Program to find all anagrams now Let's look at this, you know that Couple of things about this code it works and it was really really easy to write Now you might not believe me that this works, but I do have unit tests to prove me see me afterwards if you really don't want to so if we just look at how fast this runs then Again, we're looking at a little timing harness, you know if you're just interested in finding a few anagrams This code runs in sub second blah blah blah. It doesn't matter if you want to You know do this a lot then you start having to profile. I think that's useful to remember you know, it's only worth spending time on Speeding up code that's actually used a hell of a lot, right if you run the program once a week and it takes five hours Who cares if you run it all the time and has to run in three hours, then you have a problem So let's let's measure this So this is using Python 3 on an old laptop takes one minute 14 seconds, you know, it's not not slow, but Interestingly enough when I ran this in Python 2.7 rather than 3.4 would turn out to be faster. Hmm Not so good Because we all want to you know switch over to three Another poll who's still using Python 2? Does anybody still using Python 1? No, okay Okay, all right, so about half of you are using Python 3 You know just point out. This is this is not a general Generable Python 3 isn't generally slower than Python 2 so that's you know Go and upgrade get home, you know get back to the office switch over to Python 3 the world will be a better place So let's run this in Pi Pi and yeah, okay We've gone from you know one minute something in Python 3 Or 40 seconds in Python 2 to 22 seconds, which is pretty damn good, you know For for not doing anything apart from changing the command line But let's let's assume that you know, we have a really mean boss and he says 22 seconds are still too long to find all The anagrams in English language So let's look at profiling now Python was great. Python has a profile included Just so I can gauge how quickly to go through the profiling slides. Who knows the profiler? Okay, right the rest of you should learn it it is worth while knowing so the Python profiler is really really simple to use I don't know if you can see this Really all we do is call Python minus M to invoke the module C profile Which invokes the profiler and that spits out a huge text file here Your IDE probably how that included anyway, so just have a quick look and run it And that's spits out a file that looks a bit like this now I don't have my laser pointer, but Basically what it shows us the number of calls the time spent time spent per call the time spent In the function and in a function that calls And then the file name in the line number and you know unsurprisingly If you look at the cumulative time column, we spend pretty much all of our time in the find all anagrams functions Now in this case, that's not terribly useful If you're profiling a big program obviously finding out what functions take all your time Is the is the first step I mean there's no point optimizing all the functions you have you need to kind of apply your time sensibly so Let's see if we can do better than this You know if you just look at this function We can't really tell what's going on here. Let's see what Other tools we have now There's another profile which sadly doesn't come installed with Python by default, but it's easy to install pip install line profiler Takes no time at all All you have to do is do an app profile decorator on the function that you've previously identified as a hotspot and then We run Current prof so it's a slightly different command line not too difficult and this gives us some really interesting output so First of all, it tells us how often each line of the function is executed and that's in this case isn't terribly surprising What is I mean sometimes I find the actually the hit count more interesting than the timings Because the hit count and tells you where the hotspots are But in this case, you know all our time 99.4% of our time is spent in this if candidate and dictionary Lookup, which is slightly surprising Why it was surprising until I thought about it and you guys probably have figured this out already The problem is we're doing a linear search in a dictionary inside a linear inside a for loop So n times n gives us an o n squared algorithm not a great idea if you have large numbers of items So We can make a one-line change to this function which speeds it up dramatically And this is again slightly cheating so we just change it to a set of words It's slightly cheating because when I say it's a one-line change actually We're fundamentally changing the data structures that the program operates on But Python makes it nice and convenient to do that in this case We're looking pretty good and that now runs in 1.4 seconds, which is is Yeah, I think fast enough compared to the one minute 14 seconds that we're looking at earlier There's a slight Surprise I had after this when I ran it in pi pi And the pi pi version was actually slower Now, I mean, you know that isn't isn't terribly surprising if you if you think about a little bit with because Which it takes takes warm-up time and has to do some more work than interpret it and If your program is running now has such a short execution time Then it doesn't have time to amortize that afterwards But yeah, anyway, so there we go we have with a very simple change come to The end. Okay. Oh, sorry. Did I miss this part? Okay, well, thank you very much for bearing with me. No time for questions. Okay. Well, I'll be around For the day. So if you want to grab me grab me. Thank you