2

I have the following code that runs in about 8 seconds:

using Random

DEBUG = false
PRISONERS = 100
ATTEMPTS = 50
function tryit()
    a = [1:1:PRISONERS;]
    a = shuffle(a)
    for i in 1:PRISONERS
        if DEBUG
            println("prisoner $i")
        end
        count = 0
        check = i
        while count <= ATTEMPTS
            count += 1
            if a[check] == i
                if DEBUG
                    println("Attempt $count: Checking box $check and found my number")
                end
                break
            else
                if DEBUG
                    println("Attempt $count: Checking box $check and found $(a[check])")    
                end       
                check = a[check]               
            end
        end
           
        if count > ATTEMPTS
            if DEBUG
                println("Prisoner $i failed to find his number in 50 attempts")
            end
            return false
        end
    end
    return true
end

function main()
    tries = 100000
    success = 0.0
    for i in 1:tries
        if tryit()
            success += 1
        end
    end
    println("Ratio of success = $(success / tries)")
end

main()

Moving the global variables inside the function cuts the runtime to a tenth:

using Random

function tryit()
    DEBUG = false
    PRISONERS = 100
    ATTEMPTS = 50
    a = [1:1:PRISONERS;]
    a = shuffle(a)
    for i in 1:PRISONERS
        if DEBUG
            println("prisoner $i")
        end
        count = 0
        check = i
        while count <= ATTEMPTS
            count += 1
            if a[check] == i
                if DEBUG
                    println("Attempt $count: Checking box $check and found my number")
                end
                break
            else
                if DEBUG
                    println("Attempt $count: Checking box $check and found $(a[check])")    
                end       
                check = a[check]               
            end
        end
           
        if count > ATTEMPTS
            if DEBUG
                println("Prisoner $i failed to find his number in 50 attempts")
            end
            return false
        end
    end
    return true
end

function main()
    tries = 100000
    success = 0.0
    for i in 1:tries
        if tryit()
            success += 1
        end
    end
    println("Ratio of success = $(success / tries)")
end

main()

I could not reproduce the problem with a smaller code example. I am using Julia version 1.7.2 on Linux Mint.

Tarik
  • 10,810
  • 2
  • 26
  • 40
  • see https://docs.julialang.org/en/v1/manual/performance-tips/#Performance-critical-code-should-be-inside-a-function – Bogumił Kamiński Jul 05 '22 at 18:20
  • Also see these answers to other similar questions: [1](https://stackoverflow.com/a/34620745/8127), [2](https://stackoverflow.com/a/72655572/8127), [3](https://stackoverflow.com/a/19209606/8127). – Sundar R Jul 05 '22 at 19:00
  • Does this answer your question? [Execution time orders of magnitude longer depending upon global definition location?](https://stackoverflow.com/questions/72651825/execution-time-orders-of-magnitude-longer-depending-upon-global-definition-locat) – Sundar R Aug 28 '22 at 13:38
  • @SundarR Well, although avoiding global variables is better, declaring constants at the global scope fixes the issue. This is not mentioned in the question you pointed to. – Tarik Aug 29 '22 at 08:22
  • That's true. Could you please add a link to [the Julia manual section on this](https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-untyped-global-variables) which does mention that (and other ways to fix it), to your answer, and "accept" your answer as the solution? So that this doesn't continue showing up as an "Unanswered" question. – Sundar R Aug 29 '22 at 10:06
  • @SundarR Done both – Tarik Aug 29 '22 at 11:21

2 Answers2

0

Why globals? If you are concerned because you want to keep the variables' values global at function call for some reason, aliasing them in your function signature can fix the slowdown problem:

function tryit(PRISONERS = PRISONERS, ATTEMPTS = ATTEMPTS, DEBUG = DEBUG)
   ...
Bill
  • 5,600
  • 15
  • 27
0

Declaring the global variables as constants solved the problem.

using Random
const DEBUG = false
const PRISONERS = 100
const ATTEMPTS = 50

function tryit()

    a = [1:1:PRISONERS;]
    a = shuffle(a)
    for i in 1:PRISONERS
        if DEBUG
            println("prisoner $i")
        end
        count = 0
        check = i
        while count <= ATTEMPTS
            count += 1
            if a[check] == i
                if DEBUG
                    println("Attempt $count: Checking box $check and found my number")
                end
                break
            else
                if DEBUG
                    println("Attempt $count: Checking box $check and found $(a[check])")    
                end       
                check = a[check]               
            end
        end
           
        if count > ATTEMPTS
            if DEBUG
                println("Prisoner $i failed to find his number in 50 attempts")
            end
            return false
        end
    end
    return true
end

function main()
    tries = 100000
    success = 0.0
    for i in 1:tries
        if tryit()
            success += 1
        end
    end
    println("Ratio of success = $(success / tries)")
end

main()

See Why is there a performance difference between global and local variables in non-interactive Julia programs? for technical explanations.

Tarik
  • 10,810
  • 2
  • 26
  • 40
  • The Julia manual also has a section under Performance Tips, that deals with global variables and ways to make them performant: [Avoid untyped global variables](https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-untyped-global-variables). – Sundar R Aug 29 '22 at 12:50