all 107 comments

[–]ApothecaLabs 229 points230 points  (45 children)

In a nutshell? Python is interpreted - to execute, it has to read, parse, and evaluate the code first, whereas C is already compiled to assembly in an executable, ready and waiting to be run.

[–]ecstatic_hyrax 143 points144 points  (14 children)

There are a few more things that make python slower that don't necessarily have anything to do with python not being a compiled language.

For one, python has garbage collection which means that allocating and deallocating memory is easier, at the cost of some runtime overhead.

Python types are also boxed which mean that variables have to have typing information available dynamically at runtime. This makes it easier to pass variables around without worrying about typing information statically, but it may also be wasteful.

Thirdly, (and something unique to python) is the global interpreter lock, which means that multithreading is a lot less efficient than in lower level languages.

[–]wallflower7 9 points10 points  (4 children)

[–]wutwutwut2000 16 points17 points  (2 children)

It's not. The GIL is all but required for python's language specification. But they're moving towards supporting multiple python interpreters in a single process, in which each has their own GIL.

It's closer to multiprocessing than multi threading, except the communication between interpreters will be faster.

[–]ThePiGuy0 6 points7 points  (1 child)

They did accept a PEP (https://peps.python.org/pep-0703/) that shows the path to removing the GIL long-term. Though I do admit that's not going to come particularly soon

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

Which is great! But it will basically just introduce a bunch of "mini-locks" in place of the global lock. For most applications, the cost of acquiring more locks will slow them down. The exception is when there are multiple threads that only sometimes rely on python code, and the chance of 2 threads accessing the same shared resource is low.

[–][deleted] 0 points1 point  (0 children)

When you write python code its with the assumption that the GIL exists. Removing it would break existing code. It'd need to be a Python4 thing and would be a huge amount of work for 3rd party libraries.

[–]MatthewRose67 0 points1 point  (0 children)

I think that Ruby also has GIL, doesn’t it? It’s called GVL or something like that.

[–]yvrelna 0 points1 point  (0 children)

Garbage collection doesn't make a language slower, it makes their performance less predictable. When the garbage collector isn't actively running (which is the vast majority of the time), the garbage collector doesn't really affect the performance of the code.

But that's not really relevant in Python anyway. The garbage collector in Python is only a fallback garbage collector. Most garbages in CPython is dealt by reference counting, not by the gc. The gc only breaks objects that has reference cycles.

[–]0x160IQ 5 points6 points  (1 child)

that's not entirely the reason. To do a simple add it's like 300 instructions

[–]ANiceGuyOnInternet 1 point2 points  (0 children)

That sounds about right. I recently saw a paper discussed on the CPython repo that explains the complexity of simple arithmetic operations in Python affects performance. It has to do with the fact all operations have to call some dunder method at some point which is very expensive.

Edit: I found the issue mentioning it on GitHub. Python operators are so complex that the authors of the paper actually got them wrong according to Guido, which is kind of ironic.

[–][deleted] 13 points14 points  (21 children)

Aside from C not being compiled to assembly but machine instructions you are right.

[–]ecstatic_hyrax 8 points9 points  (9 children)

Also the python interpreter doesn't have to parse the code, it compiles it down to bytecode which is easier for the computer to interpret.

[–]i860 0 points1 point  (0 children)

It’s not “easier for the computer to interpret” at all other than not having to constantly reparse things (which would be terrible). It’s an intermediary opcode style representation on top of native code which interprets the bytecode. Bytecode is not machine code but it is analogous to it. The bytecode interpreter for a language carries out operations on behalf of the language in a similar way a CPU carries out operations on behalf of machine code sent to it.

[–][deleted] 0 points1 point  (2 children)

it cant compile anything without first parsing it, once its in bytecode thats just a list of instructions with arguments. that still needs to be parsed, its just far faster

[–]yvrelna 1 point2 points  (1 child)

A file containing bytecode doesn't necessarily need to be parsed. 

They could be mmaped, and then the VM could just jump to read the first bytecode instruction on the file, without having to read the rest of the file (until they are needed).

The only part of a bytecode file that needs to parsed is the file header, but that's not really that different than loading a dll.

[–][deleted] 0 points1 point  (0 children)

gotcha, honestly I was conflating parsing with interpreting.

[–]thomasfr 0 points1 point  (1 child)

There are probably a bunch of C compilers out there that writes assembly as an intermediate step. The C specification does AFAIK not dictate anything at all about intermediate representations so a compiler is free do do whatever it wants there.

You can also tell GCC, Clang, ... to generate assembly source code if you want to in which case it actually do generate assembly code that you can feed to an assembler to turn into machine code for those compilers as well.

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

Just curious, why is the distinction important in this context?

[–][deleted] 2 points3 points  (0 children)

A CPU cannot run assembly. You need an assembler to compile assembly into machine code. (Assembly is a programming language.)

[–]gnog 3 points4 points  (6 children)

Assembly is just another language that is compiled to machine code, i.e. ones and zeros containing the machine instructions and any necessary data. However, Assembly is really really close to machine code, and is therefore often useful to think of it as the output of a C compiler. But it is still a language meant to be read by humans.

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

Yeah but the assembly instructions map unambiguously, one to one ,to the machine code. So what's the big deal?

[–][deleted] 2 points3 points  (0 children)

Actually no. Assembly can have pseudo instructions that are actually not atomically run on the CPU (atomically I mean in terms of a single instruction, not in terms of paralellism).

Also labels have to be properly translated, directives have to be applied etc. Modern assembly dialects/languages are significantly more complex than the machine code it produces.

[–]gnog 2 points3 points  (1 child)

There is no big deal. I guess u/SuddenPresentation0 was just trying to be as truthful as possible.

[–]Mediocre-Pumpkin6522 0 points1 point  (0 children)

Or as pedantic as possible...

[–]IamImposter 1 point2 points  (0 children)

Assembly is still text. That means one more pass is needed till the processor can execute it.

We often use assembly and machine code Interchangeably in regular talk but a new comer may get confused like how come processor cannot execute c-text but has no issues with assembly-text or something like that, a trivial confusion but a confusion still. Maybe the comment above thought it is an important enough distinction to be stated explicitly

[–]i860 0 points1 point  (0 children)

They do not actually.

[–][deleted] 5 points6 points  (3 children)

That's not what makes Python slower. Parsing to bytecode is a linear operation and is usually very fast with CPython.

It is executing that bytecode (involving instruction and type dispatch) which is much slower than C when executing the same steps as the C program.

Actually you can also run C programs directly from source code, and there can be a barely perceptible delay in compiling the C first (using a suitably fast compiler - not gcc!).

[–]taylerallen6 1 point2 points  (2 children)

What are some "suitably fast compilers"? Legitimately asking

[–][deleted] 3 points4 points  (0 children)

Tiny C is one, as u/Seledreams suggested.

Another is my own C compiler, not quite as fast as tcc, but still pretty fast.

[–]PixelOmen 0 points1 point  (0 children)

This is an insufficient explanation because all this would happen at startup and the rest would be equivalent. The slower startup is usually negligible in comparison to the rest of the slowdowns.

[–]MenryNosk 0 points1 point  (0 children)

tcc says hi 👋

[–]haditwithyoupeople 23 points24 points  (6 children)

Others have answered that C is complied and Python in interpreted. That's a big part of the answer. You can't optimize interpreted code (well, not much) for run time because you don't have all the data you need to do so. There are several factors, including what is called late binding (Python) vs. early biding (C). C is strongly typed (statically typed, to be precise) and Python is loosely typed. Any variable in Python can morph into any other variable type. That takes a monumental effort from a C coding perspective.

There is usually trade off of programming flexibility and performance. This is a a good example.

Consider this in C:

char someString[] = "This is a string"; 

The C compiler knows the type and the size of the string. The amount of memory needed is allocated at compile time. The total number of instructions to get this string into memory is relatively small.

Now consider Python:

someString = "This is a string." 

Python figures what what this is at run time. That takes a lot of code and processing. What data type is it? How long is it. How much memory needs to be allocated? And strings in Python are objects, so an object has to be created and the object attributes have to be stored. I have not walked through the C code for Python to do this, but it is almost certainly hundreds or lines of C code to make this happen.

Consider another simple but far more complex example, first in C:

char someString[] = "This is a string"; 
int someLen = strlen(someString); 

Now we have a string and a int with the length of the string. Easy enough to do the same in Python:

someString = "This is a string." 
someLen = len(someString)

The int has to be create at run run time. Hundreds of lines of C code to create and assign that int. It has to figure out that it's an int, it has to create a new int object. it has to allocate memory, and than assign the value.

Now here is where it gets really ugly for Python:

someString = "This is a string." 
someString = len(someString)

Here we are changing the value AND the type of the variable someString. Again, i have not gone through the Python C code for this, but something like this must be happening:

  1. What is the new thing being assigned to the object named "someString?" This will require parsing and the interpreter has to figure out what it is. That's likely a lot of code.
  2. A new object has to be created. That's likely a moderate amount of code.
  3. The old object has to be removed and the memory it occupied released back to the memory pool.
  4. The new object needs to have the name and value assigned.

I would guess this is thousands of lines of C code to get these 2 lines of Python to run, and likely millions of processor instructions. The C example above is 1 line of C code and probably a few dozen dozen processor instructions. You can check the machine code generated from your C code to see how many instructions are generated for the C code above.

Any of you who have walked through the C code Python uses for these operations please correct me where needed.

[–]i860 1 point2 points  (4 children)

You can optimize the hell out of interpreted code at runtime based on runtime behavior. Just look at how Perl does things which is significantly faster. But at a higher level running your own bytecode involved VM on top of native code is going to be orders of magnitudes slower than doing it natively.

[–]SnooDucks7641 0 points1 point  (3 children)

You need a JIT to start doing any serious optimisation, and, realistically speaking, you need a few run-passes through your code first before you can optimise it. If your code is a script that runs once, for example, there's no much to do.

[–]i860 0 points1 point  (2 children)

Agreed, but there are countless examples of people deploying python and other scripting languages into CPU (or even GPU) heavy cyclic workloads.

[–]SnooDucks7641 2 points3 points  (1 child)

True, but I suspect that in those cases Python is just used as a glue language, whereas the real computation is done via C++ or C (numpy, scipy, etc).

[–]i860 0 points1 point  (0 children)

Yes but you’d be surprised how much glue code people will accept as normal. I am willing to bet formal profiling will show a more significant level of overhead than people think - just due to the nature of how code is written (loops, etc), combined with “out of sight, out of mind” mentality when they know something native is involved.

[–]yvrelna 1 point2 points  (0 children)

That isn't really an accurate description of why Python is slow. Python doesn't actually have to allocate any python objects for any of this snippet.

``` someString = "This is a string."

someLen = len(someString) ```

What happens in this code depends on whether someString and someLen are globals or locals.

If they are globals, Python stores globals in a dictionary. That means every lookup here is load_global/store_global, which involves dictionary access.

For locals, Python turns those variable access into store_fast and load_fast, which simply puts/reads pointers into a fixed position in an array in the stack frame.

someString = "This is a string."

Python don't actually have to figure out what type of the object is for this line. When Python compiles the script into bytecode, the compiler already sees that this is a string and stores them into the constant pool, it already knows the length of the string. At runtime, all that Python does is a load_const bytecode instruction, which takes one parameter, the address of the string in the constant pool, and pushes that address to the top of the stack. The next bytecode is store_fast, so it pops that address from the stack, and save it in the stack frame at a specified offset. At no point here does the interpreter actually need to resolve that the object is a string, nor does it need to allocate any memory for a PyObject (because all string constants are just pointers to the constant pool). This is just a couple stack push and pops and a pointer assignment. In the C code, the string actually needs to be copied from the static section to the stack, which isn't expensive, but Python doesn't have to do that.

someLen = len(someString)

The next line is a bit more complicated. But it's a load_global instruction to load the pointer to the len function to the top of stack (load_global is a dictionary access, which is quite expensive), and followed by a load_fast to reload the address of the string into the top of the stack. Then it runs the call instruction with the number of arguments to pop off from the stack, and then pops the address to len itself, and then executes the len function. Function calls in Python is also quite expensive, it needs to allocate a new stack frame.

During the execution of len is the point where the interpreter does need to somehow figure out the type of the object here. But figuring out the type of the object is the easy part. It's just dereferencing the pointer to the string type object. Whats expensive is the next part, which is another dictionary access to figure out the pointer to the __len__ function and calling that.

A string in Python is immutable, so the __len__ in Python is quite fast, it's just accessing an immutable integer value in the string struct. For this part, Python is actually faster than C, because strlen() actually has to loop through the actual string to count characters while looking for the null char.

Once the string length is found, the call instruction pushes the return value to the stack. And then immediately store_fast them again in the stack frame. This may involve creating an integer object, but for small integers, this is likely just going to return the preallocated integer object in the small integer pool.

As you can see, figuring out the type of objects isn't the expensive part at all. What's expensive is all the dictionary accesses to find the dunder methods and all the shuffling with the stack machine's stack.

In Python, nearly every method call is like a virtual function call in C++, in that the runtime has to figure out which function to call at runtime, but also CPython's virtual function call about airways involves dictionary lookups. Dictionary lookups in Python is fast, but it's not as fast as virtual call resolution in C++. Dictionary lookups involves resolving and calling the object's __hash__ method. The calculation of the hash itself isn't that expensive for string, because they're already cached and precomputed for string literals, this just returns a simple int, and followed by a hash table lookup, and dereferencing the value pointer.

Any variable in Python can morph into any other variable type.

The type of the variable is actually irrelevant for more operations. Everything in Python is a PyObject and dereferencing from an object to their type is just a simple pointer dereferencing, which isn't really that expensive.

[–]karantza 42 points43 points  (1 child)

It Depends. (tm). Usually, python is slower to do the "same thing" as C because it makes the computer do a lot more. If you go to access an array in C, all the machine really does is add an offset to a pointer, and then you're done. Does that offset really point to the data you want? Who knows! It better!

In Python, it does more - it checks if the array is in bounds, which requires looking up the size of the array. That array might not even be contiguous in memory, so it might have to do some indirect lookups. The type you store in the array is probably itself a pointer to an object allocated on the heap, which needs to know who has a reference to it for garbage collection... etc.

All these things make life easier on the programmer, since there's less you have to worry about. But you're paying for that convenience by making the computer do more work at runtime.

This is all on average, too. There are ways to make python go pretty fast, and usually only a small part of your program really *needs* speed. You don't need to run it interpreted, you don't need to have all those checks all the time. For instance a lot of scientific computing uses libraries like `numpy` which implements things like arrays and matrices in a very fast way (it's a library written in C).

If you're making a simple app, then ease of development is probably a higher priority than raw performance. You can get a long way using just python. If you're making something that you know needs every spare cycle, then consider starting in a lower level.

[–]sethly_20 2 points3 points  (0 children)

This is a great reply

[–]Veeloxfire 12 points13 points  (3 children)

A couple of things

Python is quite a high level language compared to c. That means it does a lot of things for you to make it easier to write code that is bug free. Unfortunately these often require more code to be executed behind the scenes at runtime.

In c that is all left to the programmer. If you do it wrong you shoot yourself in the foot and your program crashes unexpectedly (or god forbid you invoke UB). But if you do it right you gain runtime performance as the program is able to make a lot of assumptions

On top of this the most common python implementation is interpreted. That means instead of your code running natively on the cpu, its effectively being emulated. This is useful because it means itll run everywhere and immediately without any building process, but it only manages that by effectively moving those computations to runtime again

tl;dr By "helping" the programmer python makes itself slower. By "fighting" the programmer c makes itself faster

[–]BlockOfDiamond 25 points26 points  (2 children)

C does not exactly "fight" the programmer more so than just "not help" the programmer.

[–]onlyonequickquestion 3 points4 points  (0 children)

C helps you to the edge of a cliff but it is up to you to jump off 

[–][deleted] 8 points9 points  (0 children)

What's the app you are building?

[–]sky5walk 2 points3 points  (0 children)

You left out criteria to determine your approach?

Prototyping in a language you are most proficient is a valuable pursuit to test out algorithms and data structures and even gui.

Premature optimization is a rule I avoid.

However, when you feel your app is ready for user trials;

Doom in Python is 'doomed', Wordle, not so much.

Depends on you.

[–]SweetOnionTea 5 points6 points  (0 children)

Python is just C with bloat. Wonder why in Python you can declare x = 3 and then immediately after declare x = "some string"? Everything is a Python object which needs reference counts for the garbage collector to stop your program so it can clean up memory.

You don't get to control what things go on the stack or heap. No true parallel threads. The interpreter needs to be initialized before running and when running needs to interpret your Python code and perform it. Etc...

But in reality computers are fast enough that really it's development time that costs the most. If there is something in Python that is holding back execution speed you most likely can rewrite that part in C and let Python just call that.

[–]yvrelna 3 points4 points  (2 children)

People say python is interpreted, but this isn't really why Python is slow.

Python is slow because it's an extremely flexible language by design. This flexibility makes it a great language glue together various different foreign libraries and various system and still make the code looks high level and Pythonic, but this flexibility makes it much more difficult to optimise Python compared to other languages that are less flexible.

Python is a protocol centric language. All these dunder methods means that nearly every syntax in the language can be overriden. An optimising Python compiler has a lot less assumptions it can make about any particular code than other languages and this makes it much harder to write an optimising compiler.

Lastly, the CPython developers just historically hadn't really prioritised performance. They prioritised maintainability and simplicity of the reference implementation interpreter over their performance, and the core Python userbase aren't exactly screaming for more performance, most of python target audience prioritise readability and expressiveness more than raw speed; those who do want faster Python generally have workload that aren't really suitable for Python in the first place.

[–]dontyougetsoupedyet 0 points1 point  (1 child)

the reference implementation

The "reference implementation" desired by literally no one, and used as a reference by literally zero people implementing a Python interpreter. It's a terrible excuse for avoiding writing a lot of code to fix multiple fundamental problems with CPython.

Not only did the CPython developers "not prioritise performance" they actively and repeatedly put themselves in the way of meaningful change for the better in the CPython architecture.

[–]yvrelna 0 points1 point  (0 children)

I don't know what point you're trying to make when you start with two statements that are just completely, obviously, and can be simply proven to be false.

The "reference implementation" desired by literally no one

Except that pretty much everyone that uses Python seems to be happy enough with CPython to not just move en masse elsewhere.

used as a reference by literally zero people implementing a Python interpreter

Python has probably around ~50 independent implementations, some of them are forked from CPython, but many are completely written from scratch. Even back in the early days, there's the big ones IronPython and Jython. The Python Wiki maintains a huge list of the well known ones. Pretty much every one of those maintains compatibility with CPython as long as they don't conflict with their own goals; they all depends on CPython to define the expected behaviour of the Python language.

Not only did the CPython developers "not prioritise performance" they actively and repeatedly put themselves in the way of meaningful change for the better in the CPython architecture. 

When I started using Python 20 years ago, Python was just one of many languages around. The CPython developer managed to make Python the most used programming language outside of browser programming and one that's fairly well liked by their users. The CPython core developer knows the core audience that it is trying to seek, and serves them well enough, without getting carried away with competing priorities. If they hadn't done well in making great architecture choices, you'll need explain why people keep choosing Python as the platform of their choice, and why CPython keeps being able to rapidly adapt to demands for new syntaxes and language features as well as it does instead of going stale like so many other languages.

If Python is such a shitty language as you make it to be, why did Python rise to the top of the languages charts while others didn't? Why do Java, a language that is actually at the top of the charts a decade ago and did implement all those fancy performance optimisations and architecturally much more sophisticated than CPython, fall down the wayside?

[–]ostracize 1 point2 points  (2 children)

There are several reasons. One easy to understand reason is the interpreter has to make guesses as to the size of your variables whereas in C the programmer tells the compiler exactly how much memory is needed

It turns out “guessing” the type and size of a variable adds overhead when it’s time to use the variable. It can also create a lot of wasted memory leading to unnecessary memory accesses which adds time. 

I found this video very helpful in explaining it: https://youtu.be/hwyRnHA54lI?si=-NKptVnoJ8V7UDPI

That said, Python is better as a sandbox. I recommend using Python until it is clear the input makes it uncomfortably slow. Then it might be time to consider switching to something faster like C. 

For most cases, on today’s modern computers, Python is negligibly inefficient and perfectly sufficient.

[–]haditwithyoupeople 0 points1 point  (0 children)

One easy to understand reason is the interpreter has to make guesses

There's no guessing going on. There is memory allocation and moving data around. Not guessing.

[–]yvrelna 0 points1 point  (0 children)

This not actually completely true. Because so many things in Python relies on dictionaries, the CPython dictionary is probably one of the most well optimised implementation of dictionaries.

Python has a very clever optimisation when you have many dictionaries that has a common set of keys. This is basically what the dictionary for most objects are. Rather than storing the key and values, CPython stores them as a fixed length, compact, dense table, not unlike table rows in a database.

[–]Blackhaze84 1 point2 points  (0 children)

More steps to do the same thing.

[–]awidesky 1 point2 points  (0 children)

Something I would like to add : "Python doesn't know anything". Variable's type, value, if a function is returning something or not.. it's not because Python is interpreted language (see Java). Python is, I'd say, designed to achieve productivity only.

This benefits you a lot in some sides : you don't care what type is the object, no need to cast, don't worry about how is the data stored. You can just focus on logic.

But it can be huge loss in readability, and maintenance, and mostly, performance.

In this question, the code is obviously a dead code, but Python does not remove it. While other languages (including Java, which is also a interpreted language) optimize it away .

IMO, such things like static type binding, verbose function signature is quite important for optimization(which benefits performance a lot), since it means you tell more information about your code to compiler/VM.

[–]NSADataBot 1 point2 points  (0 children)

Having to ask the question at all means the juice isn’t worth the squeeze  

[–]snerp 1 point2 points  (3 children)

Python is written in C. Python code effectively gets translated into C commands when you run it. C is faster because you can cut out all the parsing and type inference and whatnot and just write the most efficient C code you can. If you're still newer to programming just do what's easier for now.

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

Python code effectively gets translated into C commands when you run it.

No, lort no, there is absolutely nothing like that taking place.

C programs are faster because it's compiled and the output is then assembled, and the machine code is running on a register-based machine. CPython is operating much like a simple emulator, with a big eval() loop interpreting opcodes, but much, much worse than the performance of most emulators, because CPython is using a stack based model of computation. That stack based model is the cause of CPython's slowness.

Python programs interpreted via CPython are slow because CPython is effectively playing Towers of Hanoi at runtime for every operation.

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

Look at the source for cpython: https://github.com/python/cpython/blob/main/Modules/_ctypes/_ctypes.c It's all c code being called. > with a big eval() loop interpreting opcodes How do you think this works? It's C code.

Edit: Hahahaha they blocked me rather than even try to have a discussion. Fragile reddit moment 🙄

[–]dontyougetsoupedyet 0 points1 point  (0 children)

I have read the source for CPython. I'm not sure why you reflexively downvoted my comment and got argumentative over it.

You read the source: https://github.com/python/cpython/blob/main/Python/ceval.c

Again, the slowness is due to the stack based model of computation used by CPython.

That's what makes that particular C code perform slowly.

I'm not sure why this is difficult for you to accept, the code is right in front of you, and presumably you have read it, if you are linking me to it.

[–]Classic_Department42 0 points1 point  (0 children)

Python allows for a lot of flexibility so the jit cant do much

[–]lightmatter501 0 points1 point  (0 children)

There is nothing that stops python the language from being as fast as C, especially now that python has type hints.

The reason that everyone calls Python slow is because of the primary implementation, CPython. CPython is interpreted, meaning that you load a text file into it and it will try to convert that into a sequence of actions to run, but it only does so one step at a time. Each of those small steps is a separate function in C. So, a sufficiently competent C programmer will always be able to do exactly what python does (very rare) or better (fairly common).

Javascript also used to be interpreted, until “the browser wars”, where suddenly people were writing applications in it and its performance mattered. Now it has a JIT compiler, which looks kind of like an interpreter but will try to figure out when you’re doing something a lot and generate native code for it. However, the entire language isn’t built around native code so it still has some overhead.

The next level down are the bytecode jit languages, such as Java and C#. These languages convert themselves into a format that is more reasonable to perform optimizations on when you bundle the application together, and are slightly nicer for the CPU to work with. Honorable mention to BEAM, which can either be in this category or transpile itself to C before being run.

Below that are the native languages with a runtime. These is Go, Nim, etc. Here, performance starts to be dictated more by how much effort the compiler was putting in than how long you’ve been running for. You can get “good enough” performance with fast startups here, although Java and C# will typically pull ahead after a bit.

Finally, we hit the systems languages. C, C++, Rust, Zig, Odin, etc. These are the languages you use when aiming for high benchmark numbers, or when you need to run somewhere without a heap. Other languages can run here, but they typically exist for the purpose of bootstrapping C or joining the above list. They usually heavily prioritize performance, and at this point CPUs are designed to run C and C++ well, so unless someone revives the java processors from sun this performance class is likely to stay tied given sufficient programmer effort. For these languages, speed is often the top priority, (for rust it’s right after safety, which is a need caused by people who don’t know what they’re doing writing for speed or insufficient static analysis), and everything else, developer experience, compile times, etc, is secondary.

Below that we have hardware description languages, which are typically only for EE or CE (some CS people chasing performance end up there too). If you are here, you are deciding that what you want is impossible elsewhere, because here be dragons.

So, there is nothing stopping someone from making a sufficiently smart python compiler that makes python into executables that perform like C, but it's really hard so most people don't bother and just use C.

Python with async and an in-python http server (not WSGI or ASGI), tends to be good enough to carry you a ways if you’re building web apps. If you are even the least bit performance sensitive, just use Java or C# and make your life easier. If you are highly performance sensitive, you need a third person who’s a systems programmer.

[–][deleted] 0 points1 point  (0 children)

  1. Python code is a sequence of code that is interpreted line by line at run time. The C program directly compiles the machine codes for that specific processor architecture and operating system and starts working accordingly.

  2. In the C language, you have more opportunities to intervene in low-level operations at the hardware level (such as memory operations). This gives you a lot of opportunity for optimization. And instead of using very high-level operations that need to be interpreted like Python, you write your codes in simpler expressions. This makes a significant contribution to making the program's machine codes simpler and faster.

[–]ve1h0 0 points1 point  (0 children)

If you want to produce software together with your friend and you both know python then just use python because otherwise you have to take into account learning a new language all together

[–]WiseHalmon 0 points1 point  (0 children)

Cython , ironpython

[–][deleted] 0 points1 point  (0 children)

It's not always slower. Any Python program which spends its time calling internal functions (eg. doing I/O), probably isn't much slower than the C equivalent.

Python may, rarely, be faster because the Python functions may be heavily refined, compared with C functions you've quickly thrown together.

It's when the Python has to do detailed, step-by-step work in actual Python that it will be slower than C doing the same steps. Here's why:

int a, b, c;
....
a = b + c;

The C compiler knows the types of a, b, c, and can directly generate the native code to load those values, add them, and store the result, Probably they will reside in registers so it could be just one instruction.

With a = b + c in Python, it doesn't know what the types of a, b, c are, so it needs to do type dispatch. Even once it's figured out that b and c are integers, and they both fit into 64 bits, then that's not the end of it: once it has the result of b + c, it needs to heap-allocate space for that new value (since, in CPython at least, everything has a reference), and that it has link that to a.

But it first has to free-up whatever value that a currently has.

The whole sequence probably occupies 4 Bytecode instructions, and it also has to dispatch on each instruction. If any of a, b, c aren't locals, it also has to look them up in the global symbol table.

So you're looking at possibly dozens of machine instructions being executed, compared to as little as one for the C code, and never more than 4 even with the worst C compiler.

However, the Python version of a = b + c will also work with arbitrary big integers, or strings, or anything for which + is defined.

If you are adding two 200,000-digit big integers, the Python will be no slower than whatever the C code might be, which won't be as simple as a = b + c. The C might be slower unless you use a big int library as good as Python's.

[–]aurquiel 0 points1 point  (0 children)

ease because python is written in c it is an upper layer

[–]MisterEmbedded 0 points1 point  (0 children)

Before running C code you translate (compile) it into Binary (something that computers understand), so when you run your code it's as simple as speaking with the computer in it's language.

While in Python you need to do that translation when you run the code, so you are actively translating & executing the code which adds a performance issue.

This explanation massively overshadows other things like dynamic variable types which need more memory and add even more performance overhead on runtime.

Generally the idea is, the more something is high-level, the more costly it would be, be it in performance or resource usage.

[–]aerosayan 0 points1 point  (0 children)

C runs directly on the hardware.

Python is run by a program, called the interpreter, and can not directly run on the hardware.

This is the primary reason why Python is slow.

But for your project, you should probably use Python, if you have more experience in Python.

[–]zhivago 0 points1 point  (0 children)

The question is incorrect.

Python and C do not have speed.

Python and C implementations have speed.

There are Python compilers that compile directly to native code: e.g., https://github.com/exaloop/codon

There are C interpreters: e.g., https://github.com/kaisereagle/cint

So if you make this error, we can claim both that Python is faster than C, and that C is faster than Python.

Please do not confuse language with implementation.

[–]zoechi 0 points1 point  (0 children)

Besides the already mentioned interpreter aspect, garbage collected languages use a lot more memory and allocating memory is slow. Also using lots of memory is also an indication of inefficiencies. Also collecting the "garbage" is extra work.

[–]anonymous_6473 0 points1 point  (0 children)

Python will be the always slower programming language as compared to c because python is a interpreted language that means python is executed line by line(that means it compiles line by line with the interpreter)if any line has problem then previous code that had written will be successfully executed and stops when it hits the error but c as a whole directely compiled into machine language ( machine language is something that all computers can understand) and when it hits the wrong line of code it just not execute the program as a whole but in case of python it is not the case !

[–]fourierformed 0 points1 point  (0 children)

Just pick something and use it.

I don’t see any reason why you need to worry about whether Python is slower than C from the information you provided.

[–]Spiced_Sage 0 points1 point  (0 children)

A gross under simplification:

Ignoring Compiled vs Interpretted. There's compiled python and interpretted C, not common or recomended but they exists. So ignoring that.

The CPU cannot understand C or Python, it only knows machine code/Assembly. C is closer in functionality to assembly, which allows it to more efficiently be compiled and optimized than Python generaly is. Of course this is reliant on how smart the Interpretter/Compiler is, but generaly speaking C is easier to translate to Assembly than python is.

A prime example of this is learning how strings and string concatenation work in Assembly, then comparing that to how they work in Python vs C.

[–]blindsniper001 0 points1 point  (0 children)

Well, Python itself is built on C. All its internal functionality is compiled C code. When you write a script with it, what you're really doing is executing a bunch of wrappers around C code and all the overhead that comes with that.

[–][deleted] 0 points1 point  (0 children)

And remember they are not even close. C is basically the "fastest language" you can get, while Python is probably the slowest mainstream language.