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.

Tags:

Python

Julia