13

I tried to compare these two snippets and see how many iterations could be done in one second. Turns out that Julia achieves 2.5 million iterations whereas Python 4 million. Isn't Julia supposed to be quicker. Or maybe these two snippets are not equivalent?

Python:

t1 = time.time()
i = 0
while True:
    i += 1
    if time.time() - t1 >= 1:
        break

Julia:

function f()
    i = 0
    t1 = now()
    while true
        i += 1
        if now() - t1 >= Base.Dates.Millisecond(1000)
            break
        end
    end
    return i
end
Michas
  • 195
  • 1
  • 5
  • 4
    I'm not sure how Julia works, but it appears you have to construct a new object for every comparison, while Python is doing simple integer comparisons. – chepner Apr 23 '20 at 13:05
  • 1
    Also please note that this is some sort poor's man speed comparison, isn't it? Nowadays you can make Python and Julia run roughly at the same speed with the proper amount of motivation (on both ends). If you are doing this to pick up either of the languages, look into which one it is easier for you to think with. You can optimize that later, when you actually need it. – norok2 Apr 23 '20 at 13:32
  • @norok2 That is true for some codes but not for others. If you are able to turn the Python code into a call to a library function written in a fast language, or if it's supported by numba, or something similar, then maybe, but otherwise Python is significantly slower. – DNF Apr 23 '20 at 14:16
  • @DNF There are some things where Python is faster and some other where Julia is faster. I am sure you can find examples of both. It is excessively ignoring of the complete picture to say that Python is "significantly" (whatever that may mean) slower just because of the relatively expensive explicit looping and function calls. Sure, if that is your work-horse than maybe you are better off with Julia. However, if you use the right tools, you can get equally fast in Python. Is it worth to learn these tools or is it better to learn a different language. It is hard to say. – norok2 Apr 23 '20 at 14:54
  • 1
    I use both languages, and while there are 'some' examples of both being faster, the balance is considerably on one side. It's simply a consequence of Python being interpreted and hardly focusing on performance at all, while Julia has a strong focus on performance. It's actually a lot like saying that Python is as fast as C. It would be very odd if there _wasn't_ a significant difference, and it would undermine much of the purpose of Julia. – DNF Apr 23 '20 at 14:59
  • @DNF I think you are missing the point. Saying that language X is faster than language Y is meaningless without some context (and without specifying the implementation, but let's just overlook that for now). All you can say is that implementation X' of language X is faster than implementation Y' of language Y at *this specific task*. There is no balance, there is just selection bias. Now, CPython is not focusing on numerical computing, but it is unfair against thousands of CPython developers to say that it is hardly focusing on performances. Julia may be offering more numerical tools... – norok2 Apr 23 '20 at 16:43
  • but it does not say anything about the "speed of a language", which is a poorly defined concept. Julia originally started to fit a particular niche, which is being covered by other tools in the Python ecosystem (Numba, Cython, PyPy, etc.), but it is lacking in other areas. So at the end of the day it depends on what you do, whether you are faster with one language or another. In some sense Python is as fast as C (as probably is every other language) because the compiler/interpreter whatever is written in C. The fact that two resembling pieces of code run differently on any given language... – norok2 Apr 23 '20 at 17:02
  • like a `for` loop or something, says nothing about the "speed of the language". That being said, I love Julia for some design choices, and I love Python for some other design choices. And in all honesty I would not recommend one over the other on some a priori feeling, because it literally depends on the task which one I would find a better fit, and "overall performances" is just not a good parameter to look at, because for almost any given task I can think of there are reasonable solutions that are probably within 50% in execution speed of each other, so why bothering? – norok2 Apr 23 '20 at 17:07
  • You're basically rejecting the concept of performance in general. But if any task can be reasonably implemented in Python within 50% performance, how do you explain the 'two-language' problem? – DNF Apr 23 '20 at 17:22
  • Sorry, we should not continue this discussion here. – DNF Apr 23 '20 at 17:28
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/212377/discussion-between-norok2-and-dnf). – norok2 Apr 23 '20 at 17:51

3 Answers3

13

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.

StefanKarpinski
  • 32,404
  • 10
  • 86
  • 111
5

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.

Bogumił Kamiński
  • 66,844
  • 3
  • 80
  • 107
4

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

François Févotte
  • 19,520
  • 4
  • 51
  • 74
  • shouldn't you use [`time.perf_counter_ns()`](https://docs.python.org/3.7/library/time.html#time.perf_counter_ns) in Python? – norok2 Apr 23 '20 at 13:28
  • Using time.perf_counter_ns does not change anything (at least on my system) for this benchmark. I guess that, when measuring time differences in the order of 1 second, the accuracy of the time measurement does not matter much. Only the time it takes to take the measurement and compare the resulting objects matters here (as well as the efficiency of loops themselves). – François Févotte Apr 23 '20 at 13:34
  • In Julia measurement time matters - that is why in my code I used `time_ns` not `time` as it is ~ 30% faster then. – Bogumił Kamiński Apr 23 '20 at 15:28