 Right, so hello everybody you can call me Sven and for for money stuff I do basically I'm a freelance software consultant, but for you know for fun stuff I do rust and a fair bit of that and Yeah, so today I'm gonna show you How to use rust and what to speed up your Python also how to use Python also slow down your rest I'm serious actually we're gonna look into that and Yeah, let's get started now actually as far as the conference goes I'm fairly surprised because there were like three rust talks already I believe like this was fairly surprising because like last year there was nothing and so I'm quite glad that you know This is kind of working out for us Right, so But I like I believe that I'm presenting a new method that hasn't been brought up in this conference before and I believe it's a quite quite simple and quite low and boilerplate so Yeah, let's dive just into it and also I'm gonna assume that you have no knowledge of rust whatsoever I believe the other talks kind of assumed that you did I'm gonna explain every little bit of syntax And in fact, we're gonna look into you know what rust looks like first and then we're gonna discuss the more interesting concepts All right So first of all gonna talk about the motivation like there's different like reasons for why you would want to use rust to begin with Right this different reasons now I'm gonna look at the current approaches in order to fulfill some of these motivations and then we're gonna see how we can actually fulfill the From this talk alright, so there might be multiple multi motivations why you might want to do this now Obviously the first like the most intriguing one and probably the highest impact one is take to speed up your program Right, this is always the like the primary reason, but you might also want to escape the Jill right the Gill I'm all to do some proper multi-threading right because you all know that in Python You can't do proper multi-threading without kind of running some hoops around places And also might want to bind to existing system libraries For instance, if you have like if you are a scientist, right? You want to build a bind to some existing C++ libraries This might be a thing that you might want to use like rust for for building some kind of like the the glue code right so Today we're only gonna explore the speed up your program kind of thing because I also got the vibe from the conference That this is probably the most important topic for everybody Because you know Python is kind of slow right and we want to make it kind of fast and Now the question is how do we get there? All right, but Let's let's see how we can like which ways currently exists in order to speed up our Python and as far as that is Concerned we are we know very well about the C extensions, of course Like this is probably the best documented way, but to be honest, they're quite annoying, right? You have to write lots of boilerplate code You know, it's not very not very nice. All right, then there's C types Which is kind of the the newer way to do that But you know, it's kind of discouraged nowadays and then they see if FFI which is like probably the newest way to do that But you know, it's also kind of boilerplate heavy and I don't like that. So there's Binding generators like boost Python, which you know, if it works, it's fine, right? But if it doesn't work, you get like megabytes of template messages and C++ which is not very nice and you have SWIG Which also generates Python bindings Then there's specialized lips where you can use like pillow for a for image manipulation, for instance on NumPy Which I'm sure many are familiar with which you can also use to vectorize your code And if you can fit it into that, it's great and you should probably just kind of keep it that but sometimes you just can't and you have to be You know, we have to be a bit more ingenious about that and then of course as Pipe by which we all know and love And which is just jib base approach to speeding up the program and in best case, of course You don't have to do anything which is also great and then the siphon, which is a Python dialect, of course And then there is another binding generator on the block. It's Pile 3 and this is actually what we're gonna be using Which is a rust-based Python Kind of binding generator All right, let's look at why we would actually want to like approach and this thing from a new perspective, right? So like why do we even care? So current approaches like at least the manual ones are unsafe and by unsafe I mean that you might run into data concurrency issues Like you were at run into race conditions dirty read dirty write stuff like that, right? If you have multiple threats writing the same variable like what you're gonna do So you're gonna have to handle that you don't like especially in C, right? You're gonna have to use your own memory management Which is not very nice and you might run into segmentation faults and like, you know Uninitialized memory stuff like that. So we don't like that, right? Now C is not very economic either, right? It's you know shown its age, right? Like it doesn't have very nice syntax for for solving some concepts like it doesn't have nice Lambda syntax you can kind of do it, right? But it's not really nice then you have the object which is also very nice So right, it's not very nice. So and then if you use pi pi, right? Using a jit-based approach, it's kind of unreliable, right? You might it might work. It might not work Doesn't place a nice with C types either. So not really great either Multi-threading as I just said like C and multi-threading is not the greatest, you know of words right now It's you can do it. But to be honest like Like this would probably not be your best choice if you were to speed up your problem program using that So instead we're gonna oxidize our snake or your snake essentially So we're gonna use Python and RAS in order to make an oxidized snake get it. It's like a snake, but it's oxidized, okay? All right, so What is RAS? As I said, I'm gonna assume that you have no idea about RAS and this is totally fine because the Python conference All right, so RAS is safe. You're not gonna get any problems with like data raises. You're not gonna get any initialized memory basically there's Like it's very hard for you to crash your program to quite honest, right? You can make it unsafe, but you have to be very explicit about it and Yeah, the compiler is actually a bit of a bitch about it to be honest like the you're gonna spend a lot of time fighting the compiler But in the end if it does compile you can be reasonably sure that at least it won't crash, right? I mean, of course, you can still make logic issues, right? But no programming language probably ever is gonna save you from those, right? So And also it's gonna save you from multi-threading problems and we're gonna see this actually later on why what that is So it's also modern. So by that I mean it's it has for instance like unicode support built-in There's something like even Python didn't have you know properly in the in the second iteration And it has pretty good-looking syntax. It has great amazing tooling. In fact We're gonna look at that a little bit later But basically you have a tool called cargo which is your package manager and it's also your build system And it's all that mesh into one thing and yeah, that that works out quite well and then it's fast It's really fast In fact, it's like see like fast because it compiles down to the same kind of machine code And it uses LLVM or the main rust implementation uses LLVM as its code generation Back end so that you know, you get all the benefits from that and then it's a statically and strongly typed So that means, you know that if you have a type you're gonna stick to it You can't have a like a dynamic type thing. So that also means that of course we can't do funky things like Your monkey patching a type or monkey patching variable stuff like that These are things that you're gonna be that you have to be tricky about right But it works and you can do it in rust and then it's immutable by default now And Python everything is mutable by default right you can like you have a variable You can choose to choose to change it like 20 times and it will just kind of work This is a bit of a problem really like if you think about it Basically is most of your data right? Heavy or most of your data read heavy if you think about it probably read heavy Right, so it makes sense if most of your data was immutable by default, right? And this will give you some guarantees and imagine that in Python You had a compiler which enforces this kind of behavior and then we're asking gonna be have to be explicit about making things Mutable if you want to change them and then basically just the default is gonna be that it's immutable And actually the compiler is gonna warn you in fact, it's gonna crash about that So it's also private body for that is and pythons everything is basically Importable from everywhere. I know there are some great tricks which you can do but essentially Everything is always public. So and russ everything is always private which means you're gonna be have to be explicit About which things you actually export which data structures you actually export which functions you export And this is quite cool because this way like you can't export too much, right? It's it's always better. I believe to export too little and then to export too much right and then as I said the tooling is amazing the community is amazing and I think probably the greatest point is that we have an amazing mascot. Look at that He's called Ferris and he is a really quite cute and then of course you have a fearless concurrency So watch out for that and so what does it look like right? And so here we have a rough program quite a trivial one and Essentially what you have in the top there you declare function using fn as opposed to pythons dev and Then you put in an x and it's a string type ignore the n percent for now basically means a reference So so that we don't copy this string. We're very explicit about this and we have a print lm thing Also ignore the bang there. It's a macro, but just ignore it for now But essentially you look as you see that looks kind of like the python Equivalent which is like this right and you can see that's really quite similar, right? One thing to note is that you have the lead names as opposed to just names Basically, you have to be explicit about declaring variables as opposed to changing them. So you have to have the lead there Right, but anything else looks kind of the same right the iteration looks kind of the same The the printing looks kind of the same. So it's not really all that alien to python developers, right? There's obviously some funky syntax sometimes is that you can build right and also it's braced as opposed to indentation syntax based which is nice because finally you can make you know, you can actually Formate code and an idiomatic fashion that everybody can agree to that like you know python you have people like new tabs spaces Right stuff like that. So we I think we kind of agreed on four spaces, but I know there's some companies which you think otherwise but you know all right, so That's our you know our base what we're gonna build up from and so rust and path now I think Everybody's waiting for how to actually you know make rust and python work together. So as I said, we're gonna use pyro 3 and It allows us to write Python modules and rust and Allows us to use Python from rust, you know, so we can do it like both ways We can make it like a Python module like you would more normally make like a module in C and then import it in Python But you can also have like the interpreter acquire the you know the jail the global interpreter log and then run the entire Python interpreter in rust Not sure why you would do that, but you can do that, right? So and let's make a Python module and rust so As a few things to note here, it's gonna be gonna look a bit funky at first, but bear with me So let's just ignore the feature on top there And then the external crate is basically like this is this way you tell The the code the library to use an external so-called crate now a crate is like a package Right the Python package basically just this way you open a package, right and it's on a package and then the use is basically like And Python would look like from something imports asterisk, right? And this is essentially the same now. I know that we don't like asterisk imports, but we're bear with me Yes, it's a it's a talk, right? so and then you have this funky looking pie mod in it essentially just tells us what the Modules they have is gonna look like right because in Python you have modules and in rust We also kind of do but you have to like make the bridge explicit I believe so this is how that looks like and Then you have a function you explicitly declare this function using this attribute on top. They are the pie FN And then we call it. Hello. This is gonna be the string that's gonna be put into the generated code And then conveniently it's also the same. You know the the rust function name is the same as the the symbol that we actually export And then all we do is we just have like this we take in the name is a string type And then we just print the name and then we have those weirdly looking okay, which are basically just you know empty empty results Now we I'm not gonna tell you about rust and and error management. This would be a bit too much I believe but basically just say like let's just suppose that in rust we always have to be explicit about whether we are Returning an error or a result and in this case we are returning results, right? So let's call this from Python This is just what's gonna look like So, you know like you're like any normal Python module and you're gonna see that you know This is gonna be the output and this actually works. You can actually take it like this There's no other boiler pattern. This just works like that, right? Of course, you're gonna have to have your like your cargo setup and this is not much Right, this is just like basically like your default setup that you get if you have like cargo in it And then off you go. This is all you have to do. There's no see if I shit involved. There's nothing else Right, this just works like that. So I think this is quite amazing And you can also see that we have some fancy unicode stuff in the code that also works. All right, so Let's build classes now Python is famously called a an object oriented language For good reason and that means we should probably be able to construct classes also from our rust code Now the rust doesn't have classes, but the rust has drugs now Shrugs as a kind of like just data structures which can have other data structures inside of them or other data types and So think of them like a Python class, but with some fewer bells and whistles now we can also bind methods to our structs and In fact, this is what we do here. We're using the impel statement that you see there You basically tell it that case our starting from this point forward. We are implementing this class So we are giving it functions, right? So you can you see here without our class or our struct has a list of strings like the back string is basically like list of strings It's just a vector and the vector maps to Python's list type Vector is just the same has the same properties as the as the Python list is essentially does I can grow dynamically it has One type in this case Just because Python is dynamic obviously we kind of have to bow to rust basically because we can't have like two different sets of Things in there, right? So And then we have a constructor now in Python the constructors called in it in this case We can't have in it just because basically at the time that we constructed an object in there basically because our rust code owns the While the rust code owns the pointers the the Python owns the memory So we kind of have to walk around that by giving the like making a constructor is a new and then instead of using in the like Python users in it is this is kind of weird but bear with me for a second But anyway, but what we want to show is that we can make a Struct that is gonna be translated to a Python class that we can construct in Python and then it's gonna Have this dynamic list of strings in there, which is our num strings, and we're just gonna give back the length of that Right, so let's do this in Python. This is just some Tiny little bit of boilerplate basically because it can't know which class we're gonna add the module to Sorry, which module we're gonna add the class to and then yeah, this is our Little struct there and then we can just import this Struct module that we have and then from that import the class that we've made Construct the class as you would in normal Python have the strings in there and then you know print the strings And it's gonna say that there's four strings in there. It's just fine. Alright, so let's do something more interesting, right? Let's calculate pie, but let's use a really bad way to do it And which is essentially thing about it using like want to cut it You know for me or basically imagine you have like a dart board, right? But you have only like one quarter of a dart board, right and you're throwing darts at it But you're extremely bad at it, right? So you hit a random position every time you throw a dart right and basically what you do is in just like after you've thrown The darts you count like which ones are outside which ones are inside and then using that you estimate pie It's an extremely, you know incorrect way to to you know approximate pie, but it well it will eventually converge to a correct thing, but It's it's very bad, but it does fit on this slide. So I chose to go with this So this is why we have to so in circle is essentially this method Which checks whether the dart that you throw it is inside of this quarter of a circle or not, right? And then we have a function called calc which basically just runs a number of iterations And it throws many many darts in this case We throw a billion darts at it and in the end we just calculate pie using like four times the hits Divided by the number of iterations and as a float and this why this way we get pie and We just let us run this and we're gonna end up with a really better approximate like this is one billion Rounds of this rather than we have like three point one four one six Right, this doesn't quite work. Don't do this Please ever at home and we but we take four minutes and ten seconds to do this All right, this is quite bad, right? We need to go faster, right? Let's let's make it faster so we use some rust to code to do this and Essentially, this is a more or less direct translation of that There's one new construct which we have here, which is this one dot dot iteration thing that we have Basically, this is a range like in Python you have ranges using like range one comma like iterations This is essentially the same thing but using rust syntax and then on every iteration We map like the same as in Python and as we don't care about the value like the way would be like one two three Like we don't care about that. We just want to do something for every iteration that we have Right, we could do this in a less proceed a little less functional way But there's a good reason we do this and we're gonna see this in just a little bit But anyway, so we call our random generator for every one of these iterations that we have and it's either gonna be a one If it's in the circle or it's a zero if it's not gonna be and then at the end we use the sum In order to sum up all of our hits and then just the same We just do the same calculation essentially as we did in Python and this way we're gonna get pi and This is what the binding looks like it's essentially exactly the same that we had before and We're just gonna run this like import this I run it and We're gonna we're down to five seconds, right? But still not feeling it. We need to go even faster right, so What we're gonna do is we're gonna paralyze this and we're gonna use a library called rayon Now rayon is a thing that essentially gives you iterators, but it paralyzes them So RAS does many things with iterators because iterators are fairly safe, right? They know their ranges they they can check themselves. So it's pretty cool So if you look at this code, you will notice that there's very few changes in fact There's only two lines which have changed which is this inter par iter So a parallel iterator, which is a thing provided by rayon and then instead of map We have map with now map with it's required Because you can see that there's this RNG maker, right? We have to be careful We have to be mindful of our RNG or random number generator because we obviously don't want every threat to share the same Random number generator state, right? We need they need to have different states So I have this RNG maker, which is like which we just import and essentially just make sure that we have a Very fast, but also well seated RNG at our disposal, right? So and This is exactly the same code just as the as the kind of module code and so we want to run this And we can see we're down to 1.7 second, which is pretty good now This rayon thing spawned like a threats for us because my laptop has a course But it will automatically choose the right amount of threats for your machine and it will also Do this in a very efficient manner. So it will pre-fetch tasks It will figure out how many tasks there are and it's gonna build its own worker stealing queues And they're just gonna implement this by itself and it's pretty cool and we have to do very little and in fact This is entirely safe code. So like there's no way what we could have data raises there, right? There's no way that we could mess this up, which is pretty amazing I think we did very little work there to speed up our rest program and this basically completely parallel now How do we get even faster from that? That's probably a few ways like it would probably help if it didn't use a completely stupid algorithm to approximate pilots would be a start, right But you know more realistically if we went down this road and absolutely wanted to use this algorithm You could probably use some SIMD. So like single instruction multiple data You've probably heard about SSE instructions from Intel or MMX or AVX 2 Which are some instructions you can use to speed this up even more and it's quite easy whether us you can also use iterators as a library which is exposes iterators and allows you to work on like 32 floats and parallel, which is pretty great And then of course you can do cache optimizations Which you know probably you should do this in this order because you know cache optimizations are kind of gnarly to get right Let's look at some graphs how we actually did So you can see that CPython didn't do so well and I did just try out size and just you know for shirts and giggles essentially and I'm not the size and export. I probably did something wrong. I think it's probably the slow Python RNG is what I'm thinking So let's ignore this for now pipe. I did quite a bit better at 50 46 seconds and we can see that arrest is single threaded and multi-thread You know far exceed that Thankfully right because otherwise would be feeling pretty stupid at this point Right and we can also do it the other way around right if if we're feeling that up house and Python is just a bit fast All right, we can use Arrasis is bit fast. We can use Python to slow down the rest quite a bit which is essentially we do By you know acquiring the Jill right because obviously we have like Python like rust can't cheat right even if it's Python like Even if it's rust rust can't cheat. So we have to acquire the Jill which is essentially like a mutics in this way So only one thing can operate on the Jill mutably and then we import Python And then we just kind of import like using the Python to prototype import sis And then we can just get the version from then you can see that it actually prints is just fine and This is actually you know this actually run on my system and this is what it prints But you know why would you do this to be honest? I have no idea But you can do it if you ever like maybe there's actually a reason right? Maybe if you want to import like even if you want to use some kind of art kind of Python library in the rust code I don't know but you know there you go All right, so take your ways all right rust can make your Python quite fast and the pyre 3 integration is Really quite easy. I believe right it's it's quite a joy to work with this and Which would I use it in production probably no I gotta be honest there for no particular reason is just that it's you know quite Quite young of a project. I believe it's got a great direction For the same I'm not involved in this in any way So I'm just I just wanted to show you guys what this looks like and that you can combine rust and Python with a very low Overhead very low boilerplate kind of fashion Yeah, but apart from that. Thank you for your attention and Hello Does see it does cargo generate Python files when you compile these rust code or how do I tell Pysons that there is actually a compiled rust module that I can use in Python or is there something that I have to add to a set up by I Don't quite get it to be honest. So if you if you compile the rust code, right with cargo you get some Bineries yes, you get an SO like you would get if you compile to see extension module for instance So and Python can directly import as O's. Yeah, but you have to add it to set up high so that it gets packaged with your Yes, yes, you do. Thank you Hi, thanks for the talk Does pod O3 give any kind of direct interoperability with numpy and it's a form out of arrays No, I don't believe so, but you could add traits to do this and you can do your own kind of exchange functionality during in the like where you had this pie of anything you can declare there and probably Find an efficient way to do this if in case that pie as opposed numpy exposes See a lined array and if you have that you can very efficiently do that Thank you Absolutely like Sorry, no Right, there we go. Yes. So on the third line from the end you've got sys.get version, right? in Python the I was trying to figure out how Python knew the sys module had a dot get method But it doesn't but that's not a method in sys module. That's No worries, I'll ask one one question. It's it's I mean, what would you recommend? That's like a path for learning rust? That's what like what resources have you found useful in learning rust? Oh and learning rust To be honest the there's this rust book. It just called that rust book actually version two point two point two point Oh, yes, and it's really quite good it's written by some core members of the rust team and To be honest this way you run you learn a lot of rust There's also the rust cookbook and also rust by example Which are all great resources and you can actually just kind of click the code and it will compile On some server and run in your browser and this is a quite nice way to explore that But you can also quite easily like it just install it on and basically every system will work No, you don't you like you can use in forensics, but we don't do that. So as I said like if you have a look at This syntax Here where you have basically into par itter, right? This will give you a parallel iteration over like that will just kind of do the parallelization for you And there's a library called faster and you know It will do the same thing But using simt instructions. So essentially you don't see you don't even see that it It's a simt based back end it will just do this for you In fact, we could have combined that but to be honest I thought I would get quite confusing right because you have to parallelization things going on, but basically you have three levels you have the Architecture based In forensics, which you can use directly if you're feeling like that, right? But then you have also the standard standard SIMD which is just a tiny bit above that which can abstract everything away from you And then you have crates which again built on top of that and give you very nice abstractions on top of that Which will also do like one time runtime detection and they have like ways to kind of you know fall back from AVX 2 to AVX if you Don't have that hardware. So It depends on how you want to do this, but they're like everything is there Right, is there a way to automate the generation for deployment? I mean you go in life and to a Linux system or you are working in your macOS environment You need to compile by yourself where you can somehow Automated your setup the you mean compiling of the rust instead of Including in the bundle all the SO files How do you go to production with a rust plus Python code? Well, we'll just I mean what what you can use looks like for instance You could use that in order to easily package that but to be honest I just have my setup pie and it will put the binary into there and it will just work Okay, so you are there at the binary I mean if there is a way to automatically compile in the moment that you first around the server oh I so what I see so you want to basically compile the rust code without pre-compiling that so you want kind of you want to Kind of compile in production. Yeah. Oh, I mean I Mean I suppose you could do that. There's nothing stopping you from that I would not recommend that because of the you know performance characteristics that might be a bit Hazy especially if you have a lot of rust code to compile and especially because like the the cargo instruction or the cargo build might download some other crates Which might be a security problem, right? Or you might have like proxy issues So I would certainly not recommend that but there's nothing stopping you from like having a rust binary just that okay It's about the bundle generation everything. Yeah. Yeah, I would certainly pre-generate that for production at least. Thank you, right? So thank you again for the very nice talk