Python vs Julia speed comparison
Well, that's not what I observe on my system:
Python 3.7.7
Python 3.7.7 (default, Mar 26 2020, 15:48:22)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.4.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import time
In [2]: def f():
...: t1 = time.time()
...: i = 0
...: while True:
...: i += 1
...: if time.time() - t1 >= 1:
...: return i
...:
In [3]: f()
Out[3]: 4676268
Julia 1.4.0:
julia> using Dates
julia> function f()
i = 0
t1 = now()
while true
i += 1
if now() - t1 >= Dates.Millisecond(1000)
break
end
end
return i
end
f (generic function with 1 method)
julia> f()
6339528
but note that simply using time
(i.e. comparing plain numbers) is still faster:
julia> function f()
i = 0
t1 = time()
while true
i += 1
if time() - t1 >= 1
break
end
end
return i
end
f (generic function with 1 method)
julia> f()
24742703
You probably want to use time_ns
function in Julia:
function f()
i = 0
t1 = time_ns()
while true
i += 1
if time_ns() - t1 >= 10^9
break
end
end
return i
end
On my computer it runs 10x faster than Python.
This is kind of an odd performance comparison since typically one measures the time it takes to compute something of substance, rather than seeing how many trivial iterations one can do in a certain amount of time. I had trouble getting your Python and Julia codes to work, so I modified the Julia code to work and just didn't run the Python code. As noted by @chepner in a comment, using now()
and doing time comparisons with DateTime
objects is fairly expensive. The Python time.time()
function just returns a floating-point value. As it turns out, there's a Julia function called time()
that does the exact same thing:
julia> time()
1.587648091474481e9
Here's the timing of your original f()
function (modified to work) on my system:
julia> using Dates
julia> function f()
i = 0
t1 = now()
while true
i += 1
if now() - t1 >= Millisecond(1000)
break
end
end
return i
end
f (generic function with 1 method)
julia> f()
4943739
It did almost 5 million iterations before time was up. As I said, I wasn't able to get your Python code to run on my system without significant fiddling (which I didn't bother doing). But here's a version of f()
that uses time()
instead, which I will imaginatively call g()
:
julia> function g()
i = 0
t1 = time()
while true
i += 1
if time() - t1 >= 1
break
end
end
return i
end
g (generic function with 1 method)
julia> g()
36087637
This version did 36 million iterations. So I guess Julia is faster at looping? Yay! Well, actually the main work in this loop is the calls to time()
so... Julia is faster at generating lots of time()
calls!
Why is it odd to time this? As I said, most of actual work here is calling time()
. The rest of the loop doesn't really do anything. In an optimizing compiled language, if the compiler sees a loop that doesn't do anything, it will eliminate it entirely. For example:
julia> function h()
t = 0
for i = 1:100_000_000
t += i
end
return t
end
h (generic function with 1 method)
julia> h()
5000000050000000
julia> @time h()
0.000000 seconds
5000000050000000
Woah, zero seconds! How is that possible? Well, let's look at the LLVM code (kind of like machine code but for an imaginary machine that is used as an intermediate representation) this lowers to:
julia> @code_llvm h()
; @ REPL[16]:1 within `h'
define i64 @julia_h_293() {
top:
; @ REPL[16]:6 within `h'
ret i64 5000000050000000
}
The compiler sees the loop, figures out that the result is the same every time, and just returns that constant value instead of actually executing the loop. Which, of course, takes zero time.