无法同时异步运行两个带有无限循环函数

以下是测试代码:

ch = Channel{String}(16)

function start()
    # global ch = Channel{String}(16)
    @async bar()
    @async shell()
    sleep(10)   # 不要立即结束,或者直接把 @async 放到函数外
end

# 一个Shell模拟函数
function shell()
    println("Shell 开始运行")
    while true
        print("--> ")
        input = readline(stdin)
        put!(ch, input)
    end
end

function bar()
    println("Bar 开始运行")
    while true
        # 当ch里没有数据时不想被阻塞
        if length(ch.data) > 0
            # process data
            println(take!(ch))
        end

        # [...] do other things
    end
end

REPL 中运行:

julia> include("test_async.jl")
bar (generic function with 1 method)

julia> start()
Bar 开始运行
Task (runnable) @0x000000001455eb30WARNING: Force throwing a SIGINT

只好强行退出,shell 函数就没运行,这是为何???
是哪儿阻塞了么?

1 个赞

这是我的 Julia 版本:

julia> versioninfo()
Julia Version 1.4.2
Commit 44fa15b150* (2020-05-23 18:35 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-8.0.1 (ORCJIT, skylake)
Environment:
  JULIA_PKG_SERVER = https://mirrors.bfsu.edu.cn/julia/static

你要不改一下代码,可能是shell里的readline阻塞,需要你的输入

不会是 readline 的问题,因为

println("Shell 开始运行")

这条语句都没有执行

目前解决方案是让 bar(),手动 sleep 才行!!!
最短是 1 毫秒,sleep(0.001) 也是可行的。

function bar()
    println("Bar 开始运行")
    while true
        if length(ch.data) > 0
            println("foo--" * take!(ch))
        end
        # [...]  more codes
        sleep(1)  # 非得自己加一个sleep才行???!!!
    end
end

自己手动 sleep 似乎也有好处

1 个赞

不需要使用length函数判断Channel的大小,直接使用take!就可以,bar函数改为

function bar()
    println("Bar 开始运行")
    while true
        println("foo--" * take!(ch))
    end
end

不错,直接 take! 就可以。不过之所以用 length 是想判断 Channel 里是否有数据,因为没有数据的话 take! 会阻塞 Task 的运行导致后面的语句无法执行。而我希望通道里没有数据的时候能继续执行后面的语句。

刚才没看到函数里的注释。
这样的话只能加sleep了,Julia的Task本质是协程,只有单线程,如果中间没有阻塞是不能切换到其他的Task。

1 个赞

这样子啊,我还以为 Julia 自身的 scheduler 能自动调度切换的呢

看了下文档,yield函数也可以切换Task,只要替换掉sleep函数就可以。

2 个赞