3

My code is as the following,

function getImages()
    @async for i in 1:30
        load("path/to/image$i.jpg");
    end
end
   
@time @sync getImages()

Is this the correct way to measure asynchronous runtime in Julia? I don't want to believe it because in synchronous run it takes 0.1 seconds to finish and with the @async code it shows only 0.000017 seconds.

3 Answers 3

2

You need to reorganize your code a little

julia> function getImages()
           @sync for i in 1:30
               @async begin
                   sleep(rand())
                   println("Image ", i)
               end
           end
       end
getImages (generic function with 1 method)

julia> @time getImages()
Image 2
Image 5
Image 15
Image 30
Image 4
Image 7
Image 20
Image 3
Image 22
Image 18
Image 11
Image 29
Image 9
Image 24
Image 16
Image 6
Image 8
Image 14
Image 19
Image 21
Image 13
Image 1
Image 17
Image 10
Image 27
Image 25
Image 23
Image 28
Image 26
Image 12
  0.894566 seconds (650 allocations: 37.406 KiB)
Sign up to request clarification or add additional context in comments.

2 Comments

This seems quite asynchronous but if I use load("image.jpg") instead of sleep(rand()) again it prints sequentially. Is that what should we expect, for reading files?
Przemyslaw Szufel answered it in the answer above. @async by itself do not run things in parallel, it runs them concurrently. It means, that the function can yield control to another function, and this way you have multiple processes run on the same thread utilizing CPU on 100%. It makes sense if you are downloading data from network for example: while process is waiting for server response it can yield control to another process which can send another request. But it seems it's not the case for load operation which utilizes whole thread on it's own 100% of the time.
1

Here is the correct code:

function getImages()
    myimages = Vector{Any}(undef, 30) 
    # instead of Any use the correct type of whatever your load returns
    @sync for i in 1:30
        @async myimages[i] = load("path/to/image$i.jpg");
    end
    myimages 
end   

This approach is usefull when your IO is slow. Note however that this coode is going to utilize only a single thread. Hence if not IO is your performance bottleneck such parallelization will not help. In that case you should consider using threads.

Before starting Julia run:

set JULIA_NUM_THREADS=4

or on Linux

export JULIA_NUM_THREADS=4

And change your function to:

function getImages()
    myimages = Vector{Any}(undef, 30) 
    # instead of Any use the correct type of whatever your load returns
    Threads.@threads for i in 1:30
        myimages[i] = load("path/to/image$i.jpg");
    end
    myimages 
end

3 Comments

Thank you so much! I did as you said on your @threads code but I'm getting an error that I don't get normally. Fatal error: ERROR: LoadError: TaskFailedException: concurrency violation detected
your load function might be not thread-safe (e.g. rely internal state or buffer shared between function calls). In that case you will be not able to multi-thread it (unless you modify it to be thread-safe). You could then still look at Distributed in that case.
Thank you so much for your help. I guess I'll stick to @distributed for a while.
1

Your intuition is right here! The short answer is that you're not using @sync correctly.

Quote from the doc of @sync:

Wait until all lexically-enclosed uses of @async, @spawn, @spawnat and @distributed are complete. All exceptions thrown by enclosed async operations are collected and thrown as a CompositeException.

Here the @async is NOT lexically-enclosed in the @sync expression. Actually there's no magic in the @sync macro. The @async, @spawn, @spawnat and @distributed expressions will create tasks. And @sync simply wait for them to finish.

So you manually do it like this:

julia> f() = @async sleep(1)

julia> @time wait(f())
  1.002095 seconds (9 allocations: 848 bytes)

2 Comments

Thanks for your answer!! But could you please show it in my code? I tried every combination but it still prints the numbers in order.
Well. That's another problem though. I guess you meant to use Base.Threads

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.