9 ms·
Personal thoughts about Pyston's outcome
- scriptkiddy 10y agoI for one applaud Dropbox's devotion to Python. They are really helping to move the Python community forward. I also think Kevin hits the nail on the head regarding what makes speeding up Python difficult. It's the same thing that makes writing Python so enjoyable: the object model.
- curtis 10y agoThis is not specific to just Python, but I have often wondered if it would be a productive exercise to write a static compiler for a dynamic language which also supported optional static typing. Presumably this compiler could generate code that is faster than an interpreter like CPython, but slower than what you can get out of a high performance JIT, since a JIT can do dynamic optimizations and function inlining. However, once you add static type notations, the static compiler can (for some cases) generate code that's actually faster than a JIT. Typically you'd only need to add type notations to hot spot code, and you could use profiling from previous runs to figure out what type annotations to use and where to put them. Using a JIT to generate very fast code for dynamic (even highly dynamic) languages is a really interesting topic. But it seems to involve jumping through a lot of hoops to get performance that is a fraction of what you can get out of an early 1990's era C compiler (or Pascal compiler, for that matter).
- hprotagonist 10y agoisn't that what Typescript is shooting for?
- tps5 10y agoAs far as I know there are no plans to directly compile (JIT or otherwise) typescript. Typescript is always (again, as far as I know) transpiled into javascript whereupon it gets JIT'd in the browser just like "normal" javascript. The gains that come from using typescript are productivity gains: in big projects static typing, generics, decorators, and interfaces are supposed to be a boost to productivity, not a boost to performance.
- pjmlp 10y agoI guess that might change in a couple of years if Typescript is still around and WebAssembly is widely available.
- munificent 10y agoNo. TypeScript's type system is intentionally unsound (it makes it easier to interop with JS and untyped code), which means they can't rely on types for efficiency.
- tbrowbdidnso 10y agoIt was my understanding that most/all of this unsoundness can be removed by telling the compiler to disallow a bunch of stuff using command line args, is this still not the case? Also even if you can't statically determine the types of some variables typescript seems to be able to determine it for most. If most of the objects are statically known would it give you a large part of the speed up of a totally static system? In Java and C# there's still some intentional holes in the type systems like the dynamic keyword or casting to object
- the_duke 10y agoAll of this is not really relevant for TypeScript, as it just transpiles to Javascript and ends up running on the used Javascript VM. Sure, sometimes you might be able to generate more efficient code by tailoring the emitted Javascript to the VM behaviour or using something like typed arrays for low level operations, but if the target language doesn't have support for certain things like type hinting, there is not much that could be gained.
- munificent 10y ago> It was my understanding that most/all of this unsoundness can be removed by telling the compiler to disallow a bunch of stuff using command line args, is this still not the case? Nope, it's never been the case, even with all the flags on. It's not about implicit casts, it's about soundness in the actual type rules. Here's an example: function append(array: Array<Object>) { array.push("not a number"); } var nums: Array<number> = []; append(nums); console.log(nums[0].toFixed()); If you run this, it throws an exception because String does not have a "toFixed()" method. > If most of the objects are statically known would it give you a large part of the speed up of a totally static system? Maybe, but it's hard to say. Once you have a single hole, if you can't check it at runtime right at the hole, then values of the wrong type can spread anywhere in the program. > In Java and C# there's still some intentional holes in the type systems like the dynamic keyword or casting to object Right. In the above example, Java and C# would throw an exception when you added the string to the array. This check has some runtime cost, but works. I believe TypeScript is also unsound around function types, which is harder to address because there's no easy place to know where to add the check.
- gizmo 10y agoThe short answer is that performance is as much as property of the language itself as of the implementation. You can make a subset of Python really fast, but then you can't really call it Python anymore. Think of performance in terms of how much work has to be done for a function call, for instance. If the language specifies that all function calls are dynamic, all function arguments can be anything, all type classes can be redefined and so on then those are the constraints that will hold you back when trying to make it run fast. Static constraints don't really help much, because even if you statically assert you're always passing a Person instance to a function, the class definition of Person can still change over time, and the instance itself can swap its parent classes, properties, methods, and so forth. I agree that making simple and dynamic languages with hugely complicated JIT-compilers is pretty absurd. We need new and fundamentally better languages, that combine performance, expressiveness, and much better compile-time guarantees.
- pg314 10y agoIf you haven't already, you might be interested in 'The Art of the Metaobject Protocol' [1]. It takes you step by step through the design of a highly dynamic, yet still efficient design of an object system for Common Lisp and its metaobject protocol. The key is designing the extension points and the API in a way that allows efficient implementation. In Python that never happened. It seems like they basically documented the implementation and said: 'here are the dicts containing the internals, feel free to do anything you want'. That's an approach that will never result in an efficient implementation without huge efforts. [1] https://mitpress.mit.edu/books/art-metaobject-protocol https://mitpress.mit.edu/books/art-metaobject-protocol
- gizmo 10y agoThank you -- I'll check it out. I'm familiar with CLOS, but I have never looked seriously into implementation strategies. I have read many research papers on compiler design, language design, (multiple)dispatch implementations, and I have concluded that the languages we use day-to-day are decades behind what we would be using if we took advantage of this research.
- mjn 10y agoThis is roughly what SBCL does for Lisp, compilation to native code that can sometimes be improved with optional type annotations. Coincidentally, the native-code compiler itself is named Python (it predates Python the language).
- contravariant 10y agoYou mean something like Julia?
- munificent 10y agoI'm on the Dart team, so this is a topic that's close to my heart. > Presumably this compiler could generate code that is faster than an interpreter like CPython, People have been writing static compilers for dynamic languages for ages. Lisp and Scheme have been compiled for a long time. My understanding is even simple static compilation works tolerably well for something like Scheme, but object-oriented languages like Python are a different story. In object-oriented languages, the majority of "calls" are potentially-polymorphic method invocations. In Python, even `a + b` may call some user-defined "+" method which must be looked up at runtime. If you statically compile that in a straightforward way, almost all of the resulting "static" code is just going to be calls to dynamic method lookup functions. Something like: Obj* temp1 = lookup("a"); Obj* temp2 = lookup("b"); Obj* temp3 = invoke(temp1, temp2, "+"); You won't really do anything useful at the level of native code, so you don't gain much from eliminating the interpreter's bytecode loop. In fact, you'll likely lose. That above chunk of C is a pretty verbose encoding of `a + b`. You can look at bytecode is a compression format for dynamic code of that form. The runtime cost of "decompressing it" -- the bytecode interpret-and-decode loop may be a net win over the memory wasted by the larger native code size and the cache misses and stuff caused by that. In order to statically compile a very highly dynamic language, you really do need to do some static analysis to eliminate some of the dynamism. That analysis is either very costly (slow, giant monolithic whole program compiles that take ages as in MLton) or doesn't work very well (failing to infer good static types and resorting back to lots of slow dynamic code), or (most often) both. With Dart, we have a very mature whole program compiler that does concrete type inference, and it's still both too slow to run and not effective enough at inferring good types. > However, once you add static type notations, the static compiler can (for some cases) generate code that's actually faster than a JIT. You can do that, yes, but it requires a few things: 1. Your core libraries and idiomatic user code need to actually be fairly "static" in terms of the types they use at runtime. If the code really does use a lot of polymorphism and duck typing, all static analysis can do is tell you, "Yup. You gotta do this at runtime." Python in particular is well-known for relying heavily on duck typing in its core libraries. 2. Your type system needs to be sound. Once you are within the bounds of static types, the compiler needs to be able to trust that those types are correct, with no soundness holes. Otherwise, it all falls apart. 3. You need to deal with the boundary between dynamic and typed code. Because of 1, you need to do validation when an object flows from dynamic-land into the typed area. That validation occurs at runtime and has its own cost. If you aren't careful, that runtime cost outweighs the perf benefits you get once you are in static code. The "gradual typing" folks have been beating on this for years and it turns out to be really hard. Google "is gradual typing dead" to see some of the latest soul-searching. With Dart, we had 1 since the language has always had an optional static type so typical Dart code is fairly Java-esque. We did not have 2 and that turned out to be a big problem. We have since come up with a new sound type system [1] to address that. 3 is hard, but our strategy has been to be more restrictive on what kinds of dynamic code we allow to flow into typed code. For example, you simply can't pass a List<dynamic> into a function that expects a List<int>. By the time you do all of these things, I think you discover that you don't really have much dynamism left in your system. It is handy having a dynamic type for some places, like deserialization, JSON, etc. But if you care about static compilation and perf, actually being statically typed is just so much easier, and dynamic typing doesn't really offer that much value as an alternative. [1]: http://news.dartlang.org/2017/01/sound-dart-and-strong-mode.html http://news.dartlang.org/2017/01/sound-dart-and-strong-mode....
- dagw 10y agoI have often wondered if it would be a productive exercise to write a static compiler for a dynamic language which also supported optional static typing. Isn't this basically exactly what cython is?
- LeanderK 10y agoIt's hard for me to believe that it's easier (and not only more comfortable for the engineers) to start pyston rather then rewrite their backend in go or whatever. Is dropbox really so big (not in sales, in the size of their backend) that they should manage their own python implementation? Also choosing python for their backend really seems like the wrong language. Compilers (especially JIT-compilers) are hard to get right and even harder to get performant. Since i am interested in these areas i would evaluate Graal/truffle or Jython. I only looked briefly at it, but Jython seems very un-optimised and the JVM really improved it scripting-language support in the recent years. Is there really no way to solve the native-extension problem of Jython? But i maybe wrong, any comments?
- chrisseaton 10y agoThere is a Truffle implementation of Python, but I think it's a bit out of date https://bitbucket.org/ssllab/zippy https://bitbucket.org/ssllab/zippy. I can't find any papers now but I think they had results showing that it was faster than PyPy (which is consistent with what other Truffle languages have achieved relative to RPython versions). The native extension problem can be solved in Truffle with the LLVM bitcode interpreter. We're using this to interpret Ruby's C extensions.
- LeanderK 10y agothank you. What's the status of truffle? I often hear news from the project, but i never read anything about the scope of the project. Is is highly experimental? Are people using it in production? Is it intended to be used in production in the near future? Also, if it's faster and the C-extension solved by the LLVM interpreter, what's holding it back from being used?
- chrisseaton 10y agoTruffle is a large active project working on multiple language fronts at the same time (JS, Ruby, R, C). There's a pretty long tail of things to do to go from research prototype to something people could use, but that is what we are working on at the moment. Twitter is experimenting with Graal as a Java compiler in production. The C extension problem is solved in theory. We're now working on making it something a bit more substantial that the research implementation we have talked about previously.
- denfromufa 10y agoMichael Kennedy mentioned on podcast that Dropbox is considering Python 3 with type hints. Pyston is Python 2 only and considerable effort would take to make it work for Python 3. PyPy is not that bad as they describe it in incentives to start Pyston. PyPy now has cpyext and Python 3.5 support is funded by Mozilla. Another reason is pluggable JIT to CPython such as Pyjion. This is already possible in Python 3.6. Currently you can use Cython for hot spots in your CPython apps and even release GIL.
- mhneu 10y ago"the [speed] difficulties come from Python's extremely rich object model, not from anything about its dynamic scopes or dynamic types. The problem is that every operation in Python will typically have multiple points at which the user can override the behavior, and these features are used, often very extensively. Some examples are inspecting the locals of a frame after the frame has exited, mutating functions in-place, or even something as banal as overriding isinstance." It's not typing that's the problem, it's dynamic behavior like monkeypatchable methods which require dict lookups.
- denfromufa 10y agoNowhere did I state that typing is the problem. I was explaining potential move to Python 3 with mypy.
- my123 10y agoIronPython uses the Microsoft DLR, which uses a JIT, so it's definitely possible that it would work.
- denfromufa 10y agoDLR is just dynamic runtime for dynamic languages, including IronPython, IronRuby, PowerShell, COM interop calls. JIT is for CLR runtime to compile IL byte-code.
- mhneu 10y agoThey can't support C extensions, which are basically required for any real world Python. Pyjion is a Microsoft CoreCLR JIT that can support C extensions. That's Python's next great hope for speedup via JIT.
- denfromufa 10y agoPyjion is C Extension based JIT for CPython. Pyjion only uses CoreCLR RyuJIT as a JIT compiler backend. It is NOT aware of .NET types at all. Note that you can use pythonnet for interop between CPython and .NET for both embedding and extending.
- BuckRogers 10y agoWorks has stalled on Pyjion and there's not a lot of contributors or money behind it at all. Don't let the hype get to you. As it was fairly obvious with Pyston, PyPy is still where it's going to be at.
- mhneu 10y agoKey takeaway: "the [speed] difficulties come from Python's extremely rich object model, not from anything about its dynamic scopes or dynamic types. The problem is that every operation in Python will typically have multiple points at which the user can override the behavior, and these features are used, often very extensively." Also, Kevin and Pyston's team are too modest to state this directly in this article: They made good and steady progress, but it's taken them a long time. A lot of that time was spent making them experts on Python runtime and Python JIT options. With several more years of fulltime work we could have a JIT that we all use instead of CPython. Pyston showed that certain features of Python make it slow and difficult to JIT. The best case scenario for Python's future would have been for Kevin and Pyston to work with the Python core team to decide how to tweak language features for speed (perhaps marking certain object modifications as being "slow" in the same way rust has an "unsafe" marker). With Pyston shutting down, I think the horse of python speedups is out of the barn and is never coming back. More discussion: https://news.ycombinator.com/item?id=13534992 https://news.ycombinator.com/item?id=13534992
- mhneu 10y agoOne other key takeaway from the comments on Kevin's blog: "Hi John, I share some of your disappointment in the outcome [ed: Dropbox switching hot Python paths to Go], but at the end of the day I’m an engineer because I want to make an impact as opposed to just working on interesting problems, and I think the Pyston decision reflects that [ed: the cost-benefit of future time invested vs amount of speedup we might gain is not good]. I think there are some other areas of Python performance that are very important, perhaps in the numerical computing space, and I’m currently taking a look at that. Who knows how this will all work out!" One personal comment: I still think that with two dedicated full-time engineers with the experience the Pyston guys have, some syntax tweaks could be proposed that make python more efficient. That would require working with the Python core team, which is sort of a bear given the amount of effort and time required for PEP 3118 and PEP 523. Which gets back to the question of making an impact.
- tbrowbdidnso 10y agoI don't get why it seems like languages are designed for convenience then later down the road billions of hours are spent trying to get better performance. I have seen this happen over and over with PHP, Ruby, js, and now Python. The best solution is to stop using a slow language for these types of applications. Personally I don't see a point to investing so much in these projects, since all it does is encourage developers to continue their bad behavior. "Oh don't worry about it, they're working on a JIT if performance is ever an issue" -- lead dev deciding to write something that is expected to handle 10k transactions per second a few years later in Python. If performance is ever going to be important just use a high performance language and be done with it. Then you don't have to spend years and millions reinventing the wheel like Facebook did with PHP.
- BuuQu9hu 10y ago"We needed a high level of compatibility and reasonable performance gains on complex, real-world workloads. I think this is a case that PyPy has not been able to crack, and in my opinion is why they are not enjoying higher levels of success." It's a little tiring, as somebody who regularly puts production workloads onto PyPy, to hear this bullshit. The truth is that PyPy has been regularly spanking Pyston on benchmarks[1] and has been adding Python 3 support while Pyston has struggled to handle its Python 2 commitments. It's great that you wanted to build a JIT. JITs are fun and cool. But if you just wanted shit to work, you could have used PyPy years ago and not jumped through all these hoops. Yet again, the fact is that if you invested any code into C extension modules, you picked the wrong path. Good night, Pyston; you were a cool experiment and I hope that your contributors try sending patches to PyPy next time. (Pyjion, you're next.) [1] https://pybenchmarks.org/u64q/benchmark.php?test=all&lang=pyston&lang2=pypy&data=u64q https://pybenchmarks.org/u64q/benchmark.php?test=all&lang=py...
- richardwhiuk 10y agoNot being able to use C extension modules is a killer feature for lots of large Python code bases.
- raverbashing 10y ago"Some examples are inspecting the locals of a frame after the frame has exited, mutating functions in-place, or even something as banal as overriding isinstance" Ok, they're doing all of this in their codebase? This seems like "trying too hard". Yes, they can do those. It doesn't mean it's a good idea
- BuuQu9hu 10y agoIf you don't do this, then it's not Python.
- raverbashing 10y agoI've yet to see (real-life) code that needs these.
- icebraining 10y agoIt's useful when hacking around someone else's code that you aren't supposed to change. Not sure why Dropbox would need it, though.
- Twirrim 10y ago> Ok, they're doing all of this in their codebase? They might not be, but the point in the blog suggests that standard libraries they consume do. I wonder what the value proposition is in hunting down such stuff and fixing at that level (and whether that will help performance in cpython, pypy, pyjion etc.)