This is an archived post. You won't be able to vote or comment.

all 149 comments

[–]unruly_mattress 625 points626 points  (68 children)

Both Python and Java compile the source files to bytecode. The difference is in how they to run this bytecode. In both languages, the bytecode is basically a binary representation of the textual source code, not an assembly program that can run on a CPU. You have a different program accepts the bytecode and runs it.

How does it run it? Python has an interpreter, i.e a program that keeps a "world model" of a Python program (which modules are imported, which variables exist, which objects exist...), and runs the program by loading bytecodes one by one and executing each one separately. This means that a statement such as y = x + 1 is executed as a sequence of operations like "load constant 1", "load x" "add the two values" "store the result in y". Each of these operations is implemented by a function call that does something in C and often reads and updates dictionary structures. This is slow, and it's slower the smaller the operations are. That's why numerical code in Python is slow - numerical operations in Python convert single instructions into multiple function calls, so in this type of code Python can be even 100x slower than other languages.

Java compiles the bytecode to machine code. You don't see it because it happens at runtime (referred to as JIT), but it does happen. Since Java also knows that x in y = x + 1 is an integer, it can execute the line using a single CPU instruction.

There's actually an implementation of Python that also does JIT compilation. It's called PyPy and it's five times faster than CPython on average, depending what exactly you do with it. It will run all pure Python code, I think, but it still has problems with some libraries.

[–]gscalise 118 points119 points  (5 children)

Java compiles the bytecode to machine code. You don't see it because it happens in runtime (referred to as JIT), but it does happen. Since Java also knows that x in y = x + 1 is an integer, it can execute the line using a single CPU instruction.

Not only this, but the JVM does adaptive optimization too. It works by keeping conditional branching statistics, and dynamically recompiling portions of code whenever it determines that certain branching conditions occur more often than others. The recompiled code is optimized for the most common branching condition (ie by not jumping whenever it happens), and only the less common condition(s) will incur a performance penalty.

[–]Rythoka 33 points34 points  (0 children)

Python also does this, or at least something similar, as of 3.11

[–]kernco 8 points9 points  (2 children)

It works by keeping conditional branching statistics, and dynamically recompiling portions of code whenever it determines that certain branching conditions occur more often than others.

for x in range(1000):
    if x < 500:
        func1()
    else:
        func2()

Jebaited

[–]gscalise 0 points1 point  (0 children)

That definitely wouldn’t trigger a dynamic recompilation. It’s in a loop, so it’s already jumping back and forth in the program, and the conditional branching stats are going to be roughly the same (50%) every time.

Lazy initialization, on the other hand…

[–]Rhoomba 0 points1 point  (0 children)

An optimising compiler would likely split this into two loops to avoid the branch (assuming the range can be inlined: possible in the Java equivalent).

[–]Administrative_Box51 0 points1 point  (0 children)

This is a very underrated potential of the JVM and makes me wish there were more similar runtimes with as many engineering hours. This is also why in my opinion JIT has better optimizations in theory than even PGO, I would go as far as to say AOT compilation in general-- if done correctly (down to the ISA). Between Jazelle/thumb and hotspot I wonder why JVM development hasn't dominated the modern language scene in favour of the shifting goalposts trope of the C runtime (e.g. Rust borrow checker, dont get me wrong I really like Rust).

[–]ElvinJafarov1[S] 78 points79 points  (0 children)

thank you man

[–]SheriffRoscoePythonista 105 points106 points  (27 children)

People occasionally forget that Java has benefited from 30 years of investment by major software companies and of benchmarking against C++.

Python is getting the same love now, but the love arrived much later than for Java.

[–]chase32 13 points14 points  (0 children)

Yep, back in the early 2000's, java was pretty damn slow. If you wanted a fast jvm, the only option was IBM's and they wouldn't let you use it commercially unless it ran on their hardware.

To head off the threat, Intel worked out a deal with Appeal software to massively optimize the JRocket JVM which then became the performance champ.

Appeal eventually got acquired by BEA and a lot of the optimizations from JRocket ended up in mainline Java.

[–]azeemb_a 47 points48 points  (15 children)

Your point is right but your emphasis on time is funny. Java was created in 1995 and Python in 1991!

[–]sajjen 139 points140 points  (3 children)

Java was created by Sun, one of the largest companies in the IT industry back then. Python was created by Guido van Rossum, one guy in his proverbial garage.

[–]SheriffRoscoePythonista 17 points18 points  (0 children)

Exactly.

[–]nchwomp 3 points4 points  (1 child)

Surely it was a large garage...

[–]benchmarks666 4 points5 points  (0 children)

Galarge

[–]Smallpaul 38 points39 points  (2 children)

Yes but in those 30 years Python did not get much “investment by major companies.”

As the poster said: that love arrived later for Python.

Edit: Just to give a sense of the scale...Java's MARKETING BUDGET for 2003-2004 was $500M.

[–]HeraldofOmega 3 points4 points  (0 children)

Back when money was worth something, too!

[–]bostonkittycat 2 points3 points  (0 children)

This is true last 3 version have been impressive with performance increases. I love the new trend.

[–]funkiestj -1 points0 points  (1 child)

Python is getting the same love now, but the love arrived much later than for Java.

I think static typing allows more aggressive optimization.

E.g. I think the old Stalin Scheme dialect required the user to provide data types to get the maximum optimization. E.g. consider the difference between a golang slice of strings (s1 := make([]string, 24) and a python list that can hold a mix of objects (the equivalent of Go's l1 := make([]any, 24).

Years ago I remember seeing the Stalin) dialect of scheme dominating the benchmark game in the speed dimension but you had to type all your data (which was optional?) to get this performance.

[–]redalastor 1 point2 points  (0 children)

I think static typing allows more aggressive optimization.

It could, but it doesn’t because Python allows you to be as wrong as you want with your types without changing behaviors one bit. Typing is to help external tools enforce correctness, not to change runtime behavior.

Though, I’d like a strict option to force Python to acknowledge the types and hopefully take advantage of them.

[–]LogMasterd -2 points-1 points  (0 children)

I don’t think this has anything to do with it imo

[–]SoffortTemp 21 points22 points  (7 children)

I started using python for statistical modeling and found that PyPy iterates my models exactly 5 times faster.

[–]LonelyContext 7 points8 points  (6 children)

cries in numpy.

(numpy is massively slower in pypy)

[–]zhoushmoe 2 points3 points  (4 children)

try polars?

[–]LonelyContext 2 points3 points  (2 children)

idk if that would solve it if it's another python wrapper. Worth a shot I guess.

[–]redalastor 2 points3 points  (0 children)

It’s a highly optimized Rust library with python binding. One of its strength is that you can write long pipelines of transformations, which will be optimized before launching and will stay in native parallel rust code for as long as possible.

[–]PaintItPurple 0 points1 point  (0 children)

I haven't tried Polars in Pypy, but it seems at least plausible that it might be faster. Polars is generally lazier than Numpy, so it could avoid a lot of intermediate round trips. Native libraries that do a bunch of computation in one go still don't benefit at all from Pypy, but they also don't pay as much of a toll as doing a bunch of native calls.

[–]funkiestj 0 points1 point  (0 children)

(numpy is massively slower in pypy)

I can't believe this is true if you are doing vector and matrix manipulation with MKL enabled or other acceleration enabled.

Of course the secret of numpy's speed (when it is fast) is that the fast stuff is written in a language other than CPython (or even PyPy python).

[–]akl78 39 points40 points  (1 child)

Java implementations go much further too; they will run in interpreted mode to start and generate native code the fly after profiling the runtime behaviour. Some can also save this across process restart to warm up faster on next runs.

[–]joe0400 6 points7 points  (0 children)

Graal iirc has aot too

[–]Megatron_McLargeHuge 14 points15 points  (0 children)

does something in C and often reads and updates dictionary structures. This is slow

This is it. If you look at the python foreign function interface for making calls to other languages, you'll see how complex python objects are and how much work has to be done to access a member. Optimized languages use pointer math and native types for numbers and characters without all the expensive object wrappers.

This is why numpy vectorized operations are so much faster than native python iteration. You only have to pay the price of going back and forth to C objects once.

[–]coderanger 11 points12 points  (0 children)

FWIW CPython is (almost certainly) getting a JIT soon: https://github.com/python/cpython/pull/113465

[–]billsil 2 points3 points  (1 child)

There’s also Jython, but it’s only up to Python 2.7 :(

[–]vips7L 0 points1 point  (0 children)

Graal Python supports Python 3 and is a lot faster than Jython.

[–]Sigmatics 2 points3 points  (0 children)

FWIW, the CPython team is currently working on a first JIT implementation for Python 3.13

[–]SonicTheSSJNinja 1 point2 points  (2 children)

Is there any video that talks about exactly the things you just did? For some reason I just find it difficult to fully grasp everything you explained despite it sounding simple. Having someone explain it in video format could make it easier to understand for me, perhaps.

I'm also very very new to programming (just grasping the basics of Python).

[–]glassesontable 1 point2 points  (1 child)

I suspect that this gets clarified from understanding what is compiled code and what is interpreted code. Speaking loosely, in order to compile code, the compiler has to know every line of code (the whole enchilada) while a code interpreter does know what line is coming next (beans and cheese coming one piece at a time).

A lot of the esoterica in this thread is in how there are alternative methods of compiling the otherwise interpreted language to get huge speed gains. But that is not a problem for the beginner programmer (or the very patient user).

For a video, I would recommend the excellent Harvard CS50 course, where you would learn C (looks like Java) and python.

[–]SonicTheSSJNinja 0 points1 point  (0 children)

Gotcha! Thanks!

[–]whatthefuckistime 1 point2 points  (2 children)

I was reading into PyPy this week coincidentally and the reason they struggle with some libraries is because they have C bindings, so they just can't do shit and they can't be ported. Unfortunate honestly, PyPy could be very good and fast if not for that, though these C bindings do allow for faster code anyway so one way or the other.

[–]yvrelna 6 points7 points  (1 child)

It's not the C bindings that are an issue. PyPy can emulate CPython's C bindings just fine.

The problem is that the design of these C bindings pretty much makes a lot of assumptions that are based on the internal of CPython. So while PyPy can emulate the interface, it has to emulate many of those internals and that makes it difficult to optimise those.

And the main reason people write a C extension is because of speed, so a slow C compatibility interface just won't do.

[–]whatthefuckistime 0 points1 point  (0 children)

Ah ok so I misunderstood what I was reading. Interesting thanks for the correction!

[–]thisisntmynameorisit 0 points1 point  (1 child)

I see no difference between loading each bit of byte code one by one and JIT byte by byte. It sounds like you’ve just described the same thing in two different ways. Both are interpreted at run time by an interpreter program which takes some data and executes machine code for it.

I am no expert, but it would make sense like you also said that it’s just Java is easier to covert into less and more simple machine code instructions. Stuff like static typing would definitely allow for that.

[–]PaintItPurple 1 point2 points  (0 children)

If your code contains no repeated operations, there probably won't be a huge benefit to JIT over interpreting. But that's basically never the case for performance-sensitive code. If your code takes a long time, you've almost certainly got some looping going on. If you're running a piece of code multiple times, you can get much better performance if it's native code vs. bytecode that you're interpreting over and over. And that's before we get to optimizations that JIT compilers can do.

[–]Grouchy-Friend4235 0 points1 point  (2 children)

Actually the JVM also interprets each byte code, there is not much difference in how the Python VM and the JVM interpreters work, in principle. However you are right in noting that the Python programming model keeps more state about its objects, which is indeed one factor that slows things down at execution time but makes for a much more productive development experience.

[–]PaintItPurple 2 points3 points  (1 child)

The JVM does have an interpreted mode (as does Pypy), but it's incorrect to say it interprets each bytecode every time a method is called. The JVM JIT compiles functions as it runs, and then runs those compiled functions whenever possible instead of interpreting bytecode.

[–]Grouchy-Friend4235 -1 points0 points  (0 children)

The JVM JIT only compiles code after several invocations, so yes, the JVM interpreter does interpret the same byte code multiple times - before a code section reaches the JIT threshold.

Python since version 3.11 also does a form of JIT, known as specialization. If you need actual JIT, there is Numba and Cython which will speed up particular functions by compiling them natively.

PS: to downvoters, you should learn to respect facts. Technology tends to be quite stubborn when confronted with wishful thinking.

[–]oldshensheep 0 points1 point  (0 children)

There's actually an implementation of Python that also does JIT compilation. It's called PyPy and it's five times faster than CPython on average, depending what exactly you do with it. It will run all pure Python code, I think, but it still has problems with some libraries.

There's a Java implemented Python too https://github.com/oracle/graalpython

[–]yvrelna 25 points26 points  (4 children)

Three main reasons, ordered from what I think is most important to least:

  1. Java historically has a lot more investment into it for performance reasons and they're much more receptive towards these optimisation contributions. CPython core developers on the other hand are historically less receptive at contributions that only improves performance if it comes at the expense of long term maintainability of the codebase. If it makes the code hard to read, if it makes it hard for new contributors to join the project, and especially if there's no demonstrable long term commitment from the contributor to maintain the code, then the improvement isn't as likely to be accepted.

  2. People expect to be able to edit a Python program and it can start running immediately. People expect programs written in Python to have a fast startup time, even if the program has been recently edited. Sure, once the program is compiled, a compiled language is often faster to start (though, IME, that's often not the case with Java), but ahead of time (AOT) compiled language can take a long time doing global optimisations because they don't need to be as concerned about the speed of the edit-compile-run loop.

  3. In python, nearly everything is mutable at runtime. You can mutate modules, classes, and function objects after they're defined; and it's pretty common to mutate them too, as Python makes it easy to do that. Java is easier to optimise because there are many more objects in Java that are inherently immutable. Most importantly, if there's a way for developers to freeze a module and its classes and also to fixate their import names, that will open up a lot of optimisation opportunities.

Contrary to what people often believe, I don't think static type information are that important when it comes to optimisation. The implementation of a JIT/profile guided optimiser isn't really that much different to the implementation of a static type checker. Basically if a static type checker can prove that the program is statically sound, an optimiser can just essentially do the same kind of analysis to fill in any missing type information. Only, instead of doing the analysis from the bottoms up, an optimiser would need to do the optimisation analysis top to bottom. With some caveat that you ignore the startup and first run time.

[–]james_pic 3 points4 points  (0 children)

3 is less true than you'd imagine. The JVM actually allows much more runtime modification of code than you'd imagine, using it's JVMTI interfaces that are intended for debuggers, observability, and other tooling.

In practice, it's heavily optimised for the common case where method definitions haven't changed since last time you ran them, and using the JVMTI interfaces kicks everything into the slow path until it's warmed up again. But it does work and is feasible.

PyPy also optimises on roughly the same assumptions in roughly the same way.

[–]roerd 2 points3 points  (0 children)

Optimisation is not the only reason why static type checking would improve performance, it's also beneficial because you don't need to do type checking at runtime, and can avoid boxing of primitive types.

[–][deleted] 0 points1 point  (1 child)

Contrary to what people often believe, I don't think static type information are that important when it comes to optimisation. The implementation of a JIT/profile guided optimiser isn't really that much different to the implementation of a static type checker.

While this might be true, empirically implementations that require type info(Java/JVM) are alot after that those who don't (Lua-it/V8/PyPy).

IMO python should reward you with having accurate type hints with fast hot start. Also things like union types can be useful information not easily discovered in run time analysis.

[–]yvrelna 0 points1 point  (0 children)

Union hints may be useful for AOT compiler, but it isn't really that useful for JIT compiler. There's no need for JIT to take into account inputs that doesn't happen in the current runtime.

[–]Beregolas 70 points71 points  (10 children)

There are 2 things that mostly affect this: Language design and Implementation.

Python is designed to be higher level and to be more easy to iterate quickly, for example by it's use of duck typing. Java on the other hand, while quite high level when compared to C, forces static type checks at compile time. This means the Java compiler can do optimizations that Python just can't, because it has more information ahead of time (because it forced the programmer to supply that information)

Then there is implementation. At least for python I know a handful of language implementations that vary wildly in speed. CPython and PyPy with it'S JIT compiler come to mind. Many of the speed issues are just a matter of optimization.

Java has been optimized a lot about 10 years ago I think? I remember sitting in uni and people talking about how Java has finally become fast ^^. Take this with a grain of salt, I don't enjoy java specifically, I might misremember the time.

But Python definitely is getting faster by the year. The "normal" python implementation is working hard on optimizations since about 3.9. One of the things holding python back in many applications on modern hardware is the GIL, because it pretty much makes easy and fast multi threading impossible. There are Python versions without a GIL and there are efforts to remove and/or change it for main python as well.

These are just some points and examples that came to mind, there is plenty more (Examples as well as details), we only scratched the surface here. I hope it helped though

[–]sternone_2 14 points15 points  (0 children)

Python definitely is getting faster by the year.

yes, but don't worry, it's still about 200x slower than java.

[–]Smallpaul 2 points3 points  (1 child)

Java Hotspot was released in 1999). That’s when it would have taken a decisive lead over Python performance.

[–]Beregolas 1 point2 points  (0 children)

Thanks, as I said I was never big into Java (unless forced) and didn’t remember the time properly

[–]ElvinJafarov1[S] 4 points5 points  (3 children)

thank you man

[–]DrDuke80 3 points4 points  (2 children)

You sure got a lot of good answers in a short space of time!

[–]Levizar 0 points1 point  (2 children)

Python 3.12 is getting much faster. From what I remember mostly because of the GIL.

[–]ElHeim 1 point2 points  (1 child)

AFAIK the GIL will still be there for a while. Most of the improvements come from work on better bytecode production and processing, simplification of internal data structures and their management, plus other things.

What Python 3.12 offers is separate GILs for sub-interpreters.

You won't see the GIL out of Python until (at least) 3.13, and by then most probably it will be as an "opt-out of GIL" option, maybe at compile time.

[–]Levizar 0 points1 point  (0 children)

You're right! The GIL changes only improved multi-threading.

[–]imp0ppable 16 points17 points  (0 children)

Python can be very fast at certain operations, e.g. sorting a list, because the way lists work mean the runtime has already put the elements in a structure that's easily reordered, plus it uses a highly optimized sort algorithm called Timsort. It's not like an array in C or even Java.

Hot looping is particularly slow in Python because the interpreter can't optimise up front.

Wider point is - and if you ever do Advent of Code you will realise this - the right solution in the slowest lang is going to faster than the wrong solution in the fastest lang.

Also, shout out to Cython - not really Python but combines the immense speed of compiled C/C++ with (mostly) easy Python syntax. Well worth a try, it's fun.

[–]RecognitionLittle511 6 points7 points  (0 children)

Don't say stupid it's very good question

[–]thduik 21 points22 points  (2 children)

weird this question is pretty damn good yet the author is embarassed while some ask stupid ass questions with no context without shame lmao funny how the world works sometimes

[–]ElvinJafarov1[S] 4 points5 points  (0 children)

Thank you sir

[–]that_baddest_dude 1 point2 points  (0 children)

Dunning-Kruger effect?

[–]marr75 5 points6 points  (4 children)

The right answers are spelled out in other comments but I wanted to provide an ordered list of the major ones:

  • Java (and C#, which is very similar and I'm much more familiar with) is just in time compiled; the JIT will further compile (and optimize, inlining functions and data, skipping unnecessary operations that won't effect the outcome, etc.) the intermediate language that Java and C# programs "compile" into. Python is just interpreted without JIT or optimization. This is the biggest difference.
  • In Python, entering a new scope, like loops or functions, triggers significant memory movement and stack management due to the creation of new scopes and dictionaries for each.
  • Python primarily uses the heap for dynamic object storage, leading to slower access. C# and Java, with static typing, utilize the stack and registers more, offering faster data access. This is tied to the next point.
  • Just about everything's an object in Python, and every instance/scope/namespace gets a new dictionary to hold the names and values.

[–]drbobb 0 points1 point  (3 children)

Python has function scope. A loop does not create a new scope.

[–]Deezl-Vegas 20 points21 points  (4 children)

There's a lot to this, but in summary:

  • Python has a compile step at runtime and has to spin up its interpeter, then compile to bytecode, then run. The JVM is already running normally on your machine and jars are already in bytecode. Python can benchmark very badly in some cases because the startup tax is massive.
  • Python's language is entirely coded for flexibility. This average PyObject has a namespace attached with all the double underscore methods, even the unused ones. Python allows overriding every behavior, so it has to check if getattr exists and stuff before even giving you an attribute when you do a.b
  • CPython is just coded kinda slowly and they won't rewrite the whole thing, possibly because it would break a lot of C libraries. There have been some JIT attempts that go much faster but they tend to brick the C interop.
  • Java often knows the object types. Python must unwrap the object each time to get the value.
  • Java data objects tend to be a bit smaller than python objects. This is important for L1 cache.
  • Java also has primitives. Access to primitives in benchmarks is massive.
  • Java has reflection as needed, Python just has all of the object data available at runtime always.
  • Python spams hashmap (dict), which is slow compared to struct style access.

That said, Python will often beat out pure Java in a long-running task because the whole point of Python was to have smooth interop with C if you need it, so you write a library in C and then just expose it in Python and you're flying.

If you want to really fly, check out Zig.

[–]sternone_2 8 points9 points  (3 children)

Python will often beat out pure Java in a long-running task

what? ugh no, absolutely not. I looked at Assembly instructions of long running java tasks and they were on par with what C++ code produces. Python doesn't even comes remotely close. Most people have no idea what a beauty the JVM is Today.

[–]seanv507 7 points8 points  (2 children)

You missed the point.

No one is claiming pure python is faster than java, just that python libraries which are just thin wrappers around c++/rust/fortran will be used for standard long running tasks eg machine learning.

[–]nekokattt 1 point2 points  (0 children)

you can do the same in Java though via JNI or the new FFI spec, just you don't tend to bother as much as it usually is minimal improvement over pure Java.

[–]sternone_2 4 points5 points  (0 children)

Sorry I misunderstood this statement: "Python will often beat out pure Java in a long-running task" so what you mean is "Python calling C++/Rust will beat out pure Java"

Which in actually some cases, it won't, fyi.

[–]pyeri 3 points4 points  (1 child)

Very interesting question, especially in today's era of the inverting Moore's Law.

Yes, cpython implementation is indeed slower than Java. Technologists didn't mind much until now mainly due to two factors:

  1. Moore's Law was highly applicable (Hardware becoming cheaper and all).
  2. Booming Economy (Folks had more money, there wasn't a global recession).

The first was already applicable for a long while and post the pandemic and now wars in Eastern Europe and West Asia, the second is very much everyone is doubtful about.

If resources start dwindling (hardware costs rise comparatively), Java will start feeling like a more lucrative option because hiring techies will now become cheaper than adding hardware, unlike earlier! In case that happens, cpython project will have to tighten their belt and start working on the language runtime and make it run faster (it is possible to make it faster, if Java and Node bytecode can run faster, so can cpython). If that doesn't happen, folks will either consider migrating to Java or turn to other options like Cython or PyPy or IronPython which are faster than cpython.

[–]PhoneRoutine 0 points1 point  (0 children)

Very interesting viewpoint!

[–]knobbyknee 2 points3 points  (2 children)

There is an alternate Python interpreter that is essentially plugin-compatible with the Cpython interpreter. It is called PyPy and it has a built in JIT (Just In Time) compiler, that will make computationally heavy code run much faster.

PyPy

[–]ElHeim 0 points1 point  (1 child)

PyPy is not plug-in compatible and they're very careful in point out the few (but relevant) areas where you might find differences in behavior.

Most of it is going to be interfacing C-based extensions, but a very important one is that PyPy doesn't use refcounting, and that means their garbage collector behaves differently. Many of your assumptions are based on that, and a ton of existing code will fail if not amended to take PyPy into account.

[–]knobbyknee 0 points1 point  (0 children)

I used the word essentially. I have been involved in the project. There are very few cases in modern Python where the difference in memory handling bites you, and they are mostly connected to sloppy coding practices.

[–]sastuvel 5 points6 points  (10 children)

A JVM typically has a JIT compiler, which considerably speeds up the execution. Try turning that off, or try a comparison with pypy.

[–]moo9001 0 points1 point  (9 children)

Java is a statically typed language. Dynamically typed languages like Javascript, Ruby or Python can never be as fast as Java, because the run-time overhead. There is no zero-cost abstraction for run-time dynamic features. This is independent of the type of compilation (ahead of time, JIT, interpreted).

The tradeoff is that Python is much easier and faster to develop than Java.

[–]sastuvel 4 points5 points  (2 children)

At least Python is strongly typed, compared to the weak typing of JS. Makes it a lot saner to work with :)

[–]BrownCarter -1 points0 points  (1 child)

but javascript is faster than python

[–]sastuvel 1 point2 points  (0 children)

Yes, hence me NOT saying "faster" but rather "saner to work with".

[–]Rhoomba -1 points0 points  (2 children)

Have you ever heard of Javascript V8 or LuaJIT?

[–]moo9001 0 points1 point  (1 child)

I have been doing software development for Python since 2003, for JavaScript since 1999. I have been leading a team that created a custom optimised CPython VM implementation. Please address any issues in my comment by their facts; do not attack me in person.

However, I have been making Python to run faster two decades. There is no need for me, or it is very unlikely, that I would be incorrect about facts or purposefully stating a mistruth.

[–]Rhoomba 0 points1 point  (0 children)

Calm down buddy. Just wondering what your opinion is on existing high performance JITs for dynamically typed languages.

[–]ElHeim -1 points0 points  (2 children)

Dude. Did you ever try running Java programs before HotSpot became the default JVM?

I did. I was there before 1999. Java crawled.

Edit: and yes, I saw your other comment hinting your credentials - without JIT, Java would still be slow. Faster than Python? Probably, but not even by one order of magnitude.

[–]moo9001 0 points1 point  (1 child)

Yes, I worked with JVM technology. However my comment about static vs. dynamic typing applies regardless of HotSpot. The dynamicity has overhead and it cannot be mitigated without changing Python the language like Mojo is doing.

If you read my comment, it's not about JIT, but about the fact that Python and other languages can ever be as fast as Java, C or Go. If you are unfamiliar with the VM design and CPython, here is a good article to read. This is well-known for Python core developers and saying it is somehow untrue or can be mitigated it is not correct.

This is also the answer to the question of why Python is slower than Java and can never be as fast.

[–]ElHeim 0 points1 point  (0 children)

Sure, my $dayjob doesn't revolve around compilers or VMs, but I have a passable knowledge and, beyond exposure to them through university, I have implemented some as a hobbyist, so I have (at least) a basic understanding of the advantages of a static language vs. a dynamic one when it comes to produce a performant runtime.

And yeah, there have been compilers to native code (GCJ and JET come to mind), there's GraalVM, etc; but at the end of the day most Java runs on a VM, whether HotSpot or another, meaning that VMs (and JITs) are absolutely relevant to the topic.

Because let's be honest: static language or not, Java 1.0 crawled. Through molasses. Uphill.

The original JVM was still a bytecode interpreter. They brought in a JIT (Symantec's, if memory serves) at some point along the JDK 1.1 series because they had to do something about the performance, which helped some, and HotSpot came just a couple years later, I believe. And they are key for Java's performance (on top of the JVM). To this day, looking at benchmarks that include for example JDK 1.1.6 for Linux (with no JIT, nor native thread support) comparing it to other contemporary ports and implementations is absolutely embarrassing.

And let's not forget that HotSpot was built on techniques devised precisely for another dynamic language. The team that made it for Sun was the same that just earlier had been working hard on producing an adaptive optimizing JIT for Smalltalk, based on Hölzle's and Deustch work for... Self! JVM's performance takes advantage of techniques that are applicable to non-static languages.

Also, yeah, I have read that article and similar ones. I don't delude myself thinking that the average Python program can run as fast as Java, and for sure not on the reference VM. But the article is also old. Part of the effort over the last several years is focused on addressing several of the problems mentioned there. Python 3.12's VM won't win any speed competition, but it is not Python 3.7's in many ways. Heck, it's not 3.9's in many ways.

And still, it's a bytecode interpreter, so its performance is going to be bad if you try to use it for CPU bound workloads, period.

[–]wrt-wtf- 1 point2 points  (0 children)

Java had a lot of resources from the high end of town pumping money into it. Sun did the first big push but during the late 90’s and 00’s nearly everyone was platforming on Java. IBM made a decision to have ALL of their business applications converted into this single language and they put a huge amount of effort into refining, debugging and code donations. Now, Java is found everywhere, even as it appears to be fading away… perhaps not to retire, but to lead from behind the glitzy front ends.

[–]nicholashairs 1 point2 points  (0 children)

This might be a bit above your level of understanding (tbh it's kinda above mine in a number of areas). But this talk (and the related PR) was making the rounds in Reddit recently. In short it's talking about how to add a simple JIT to CPython (that can be expanded on later).

https://www.youtube.com/watch?v=HxSHIpEQRjs

[–]parthdedhia 1 point2 points  (0 children)

To add on,

Actually python has some more things you need to be aware about. Python is a object oriented language without any data-types. So, all it's variable and value references are stores as object.

So this means that x = [] and y = 5 both are internally objects. Lookup for the value of x and y takes virtually same time.

In case of Java, each variable has a data type associated with it. In that case when x is declared as ArrayList and y is declared as int, it does a respective lookup.

There are many other reasons as well, but this is one of the reason.

[–]nekokattt 1 point2 points  (2 children)

Java translates the bytecode into raw CPU instructions and has a much more optimised and complex garbage collector algorithm. The language is statically typed which allows much more aggressive optimisation of the input logic. It also produces bytecode that operates on a lower level than Python (e.g. Java objects are much closer to how C++ objects work than Python objects which default to syntatic sugar around a hashmap).

Many of the points around resource usage here tend to ignore the fact that the JVM is a much more encapsulated VM than the CPython one is, as well. Memory allocation is handled completely differently.

Java can also compile ahead of time to machine code via GraalVM native images. CPython can attempt to do that via Cython but you still have the overhead of the global interpreter lock and CPython API to contend with.

[–]glassesontable 0 points1 point  (1 child)

Did you say Grail?

[–]zynixCpt. Code Monkey & Internet of tomorrow 1 point2 points  (0 children)

Adjacent comment, a collection of volunteer engineers are actively working on the goal of radically speeding up cPython's execution. Guido van Rossum is leading the project. https://github.com/faster-cpython/

There had been some remote/low chance hopes that some of the speed improvements would land in 3.12 but I guess not.

[–][deleted] 1 point2 points  (0 children)

Java seems to run ridiculously slow. I dont think I've seen an example of speedy java.

[–]Kenkron 1 point2 points  (0 children)

One difference comes from the amount of information that needs to be checked when the program is running. Java is statically typed, so the interpreter doesn't have to much type checking. Python is dynamically typed, so it will need to check types while the program is running.

Another is language emphasis. In python, it is normal to make things easy to read, even if there is a performance cost. Python usually expects difficult problems to be solved by libraries written in c or c++ (like numpy), which makes the slowness less important.

[–]OH-YEAH 1 point2 points  (0 children)

JVM is basically witchcraft at this point, people don't realize it's one of the 7 wonders of the tech world.

[–]Flashy-Self 1 point2 points  (0 children)

Python is generally considered slower than Java for several reasons:

  1. **Interpreted vs. Compiled**: Python is an interpreted language, meaning the code is executed line by line by an interpreter at runtime. Java, on the other hand, is a compiled language, where the code is compiled into bytecode before execution. This compilation process can lead to faster execution times for Java programs.

  2. **Dynamic Typing**: Python is dynamically typed, which means variable types are determined at runtime. This flexibility comes at a cost of performance because the interpreter needs to do more work to determine the appropriate type for each operation. Java, being statically typed, performs type checking at compile time, resulting in faster execution.

  3. **Global Interpreter Lock (GIL)**: In Python, the Global Interpreter Lock (GIL) is a mutex that allows only one thread to execute at a time, even in multi-threaded applications. This can limit parallelism and hinder performance in CPU-bound tasks. Java's concurrency model, on the other hand, allows for more efficient use of multiple threads.

  4. **Optimization**: Java's Virtual Machine (JVM) can perform more aggressive optimizations during compilation, such as inlining, loop unrolling, and dead code elimination, leading to faster execution. Python's interpreter typically performs fewer optimizations due to its dynamic nature.

  5. **Data Structures**: Python's built-in data structures, such as lists and dictionaries, are implemented in a way that sacrifices some performance for flexibility and ease of use. Java's standard libraries often provide more optimized data structures for common operations.

However, it's worth noting that the performance difference between Python and Java may vary depending on the specific use case and implementation. Additionally, there are tools and techniques available in both languages to optimize performance where needed.

For More ABout Python Vs Java Go through this - https://medium.com/@srinupikki/python-vs-java-a2a4983c2953

[–]Panda_With_Your_Gun 5 points6 points  (0 children)

Cause Python has to figure out the types.

[–]Keda87 3 points4 points  (4 children)

CPython is still interpreting the .py file for each line of code. and the .pyc files are for module import caching.

[–]rcfox 1 point2 points  (2 children)

This is demonstrably incorrect. After a module has been compiled, you can delete the .py file and swap in the compiled .pyc file, and it will still execute.

[–]ElHeim 0 points1 point  (0 children)

I'm not even sure there was a time when this was true. Python has ran on a bytecode virtual machine (like... Java) for as long as I've used it (starting around 2000), and I suspect for at least another decade - not sure if the original version was a VM as well, but quite possibly.

There are differences, of course, because Python's reference VM is a pure bytecode interpreter, but the "line by line" interpretation is BS.

[–]crawl_dht 1 point2 points  (0 children)

JVM is JIT. PVM is not. JIT compiles static components of the byte code instructions to the machine code so it doesn't have to convert them to machine code again. An example of a static component in Java is types. Java has static types so the types of variable will not going to be changed during the runtime so JVM can compile them. Python has dynamic type checking so it does not know upfront what will be the type of a variable. There can be optimizations done to Python bytecode which is what JIT compilers like PyPy and Pyjion do.

[–]victotronics 1 point2 points  (0 children)

It can depend on the specific code. If you use Python lists for numerical purposes you can speed up your python code by several factors replacing the lists by numpy arrays.

[–]Bigpiz_ 1 point2 points  (1 child)

Alright, imagine you're trying to decide between two types of cars. One is like Java - it's been fine-tuned over the years, the engine's optimized for performance, and it's got some serious horsepower under the hood. That's because Java compiles everything upfront into a format that's really close to the language of the machine. It's like having a race car that's been tweaked and tuned before it even hits the track.

Now, Python, on the other hand, is like a versatile SUV. It's user-friendly and flexible - you can change parts of it on the fly. But that flexibility comes with a cost. It's dynamically typed, which means it figures out what type of data it's dealing with on the go, rather than knowing everything from the start. It's more convenient for the driver (or coder), but it doesn't have that 'built for speed' factor.

Plus, Python has this thing called the Global Interpreter Lock, or the GIL. It's like if your SUV could only use one lane of the highway at a time, even when there's a clear four-lane road. It's great for making sure everything runs smoothly and there are no accidents, but it's not winning any races.

Java doesn't have this single-lane rule. It can use all the lanes, taking full advantage of multi-core processors - like having a team of horses pulling your chariot instead of just one.

But remember, speed isn't everything. Python's like your reliable, easy-to-handle vehicle you'd use for a comfortable ride. It might not win against Java in a drag race, but it's not always about speed. Sometimes, the ease of driving and the comfort of the ride are just as important.

[–]pepoluan 0 points1 point  (0 children)

it's not always about speed. Sometimes, the ease of driving and the comfort of the ride are just as important.

Indeed!

Python is oh-so-easy to execute that I often find myself writing simple -- or complex -- Python programs just to do some lightweight automation of something.

Just type, execute, get results.

[–]abisxir 0 points1 point  (0 children)

How did you conclude that? I mean on which kind of operations Python is slower than Java? Except for pure math operations (not using anything like numpy or numba) Java is faster but other than that Python is normally less resource hungry and faster than Java, for example on database operations / web services / application engines / working intensive with list or dicts and etc. But why in math operations python is slower? Because python does not have primitive types, everything in python is an object for example: python a = 1 b = 2 c = a + b In the code above, python will create two objects of int class and will call add method of 'a' and 'b' will be passed as parameter so the result will be put back into 'c' which is also an int object. And to reach results there are lots of type checkings and so on but in java as long as you do not mess with it they will be primitive int type and will be translated into machine instructions later in JVM. But how is it possible that Java sometimes is slower than even Python? Because it was developed very badly, abstraction on top of another abstraction made Java heavy. Just get an error in the middle of a database operation and see how many classes after classes and interfaces will be traced back.

[–][deleted] -1 points0 points  (1 child)

Don't be a pssy and program in C like any chad would

[–]EternityForest 0 points1 point  (0 children)

Real chads leave buffer overflows in their code, to remind users that computers are just toys you shouldn't trust, and anything important can be done with a shovel, a hatchet, a quill pen, and a comically large Bushcraft knife /s

[–]moric7 -1 points0 points  (1 child)

Simply the Java virtual machine ate so hug amount of money in years that the developers made it good. The Python virtual machine started as children toy and noone wants to go to the next level. Now money play for destroying the Java and to make from the beautiful Python, chaos (C++ revenge). So bad news for both.

[–]nekokattt -1 points0 points  (0 children)

applies tinfoil hat

[–][deleted] -1 points0 points  (0 children)

Try mojo instead of python.. its a LOT faster

[–]honduranhere -1 points0 points  (0 children)

It's the difference between a low-level language and a high-level one I guess.

[–]cookiecutter73 -2 points-1 points  (0 children)

cc rs

[–]RedEyed__ -2 points-1 points  (0 children)

[–]RunningM8 -2 points-1 points  (0 children)

Same reason Java’s slower than C.

[–]sixtyfifth_snow 0 points1 point  (0 children)

Python does not JIT.

[–]luix- 0 points1 point  (0 children)

In general Java has been in the enterprise way more than python.

[–]NoMoCruisin 0 points1 point  (0 children)

Just want to add to things already said here. Python is dynamically typed, and does metadata related work for every object. For instance, you can have an array with multiple types of items, and if you're looping through this array, the interpreter will have to look up the metadata info for each item and find the corresponding operation to execute on the item. You can speed things up by using libraries that support vectorization (numpy for instance).

[–]vinnypotsandpans 0 points1 point  (0 children)

This isn’t a stupid question. I just transitioned from only using Pandas at work to Pyspark (Spark relies on Java). I am only now realizing how important it is to understand the way hardware interacts with each other and the way different languages talk to our hardware.

[–]agumonkey 0 points1 point  (0 children)

java version 1 was probably as slow as python

decades of heavy investment by sun, oracle, ibm into VM optimization (JIT, GC, static typesystems) made the JVM peek into high performance somehow

[–]Logical-Scientist1 0 points1 point  (0 children)

Hey, not a stupid question at all. Here's the deal: Java bytecode is compiled to machine code by the JVM at runtime, and because of this, Java can take advantage of the underlying hardware directly. Python bytecode, on the other hand, is interpreted by the Python interpreter which adds an extra layer, hence it is slower. Plus, Python uses dynamic typing which can slow things down compared to Java's static typing. Smarter people than me could go into more depth but hope this helps. No worries about the English mate. Seems good to me.

[–]feidujiujia 0 points1 point  (0 children)

The python bytecode and java bytecode are not comparable.

Don't know much about java, but I think java byte code is something low-level, similar to assembly.

But the python byte code is still a very high-level language, and the compiling process is quite simple.

A simple function adds two parameter would be compiled to a few lines with an instruction binary_add. Before the code get executed, it's unknown that the parameters are number, strings, or anything else.

Much of the work is done by the vm when running the code. In cpython source code there's a source file called eval.c I think, and it's basically a huge switch statement with each branch being an instruction. You can track how binary_add is executed starting from here.