今天的章節會先介紹Julia中的Asynchronous programming。
相信大家在其他語言多多少少有碰過這類東西,像是網頁前端、寫concurrency的時候等等都會碰到。
我們先從generator開始吧!
generator可以在你每次跟他要資料的時候吐出結果,你跟他要一次就吐一次,他不像comprehension一樣一次把結果都算好吐給你。
如此一來,在計算大量資料的時候不會事先佔去大量記憶體,只在有需要的時候計算結果並回傳
function countdown(n)
println("count down from ", n)
while n > 0
produce(n)
n -= 1
end
end
以上我寫了一個會倒數的function,在呼叫他的時候你要先給他一個數字,當你每次呼叫他的時候他會從那個數字一次一次倒數,並且把數字回傳回來。
x = Task(() -> countdown(5))
println(consume(x))
回傳
count down from 5
5
println(consume(x)) # 4
...
接下來我就不列了,大家會注意到一對函數,produce()
跟consume()
,他們就像yeild
跟send
一樣,一個會負責把回傳的值丟出去,一個負責呼叫並且接收值。
在Python裏面有個東西叫作coroutine,他是個好用的東西,他可以像function一樣被呼叫之後暫停,然後先去做別的事情,之後再回來這邊完成後面的事情。
在Asynchronous programming中是少不了他的,基本上他不會佔到額外的記憶體空間,像是如果function被呼叫的時候,電腦會配置給他額外的記憶體空間,當function的數量變多,記憶體空間也會隨之被消耗,相對,呼叫coroutine不會佔去額外的記憶體空間。
相對應coroutine的概念,Julia把他包裝成一個有狀態的物件,稱為Task。
我們來看看Task的作用吧!
function add_something(n)
x = produce("我們開始吧!") # 會吐出值給consume()
while true
x = produce(x + n)
end
end
foo = @task add_something(100) # 這是一個task,等同於 Task(() -> add_something(100))
我們定義一個Task,他會把我們一開始給的值n
加上他後來接收到的x
,然後把他回傳給我們。
println(consume(foo)) # 我們開始吧!
println(consume(foo, 5)) # 105
println(consume(foo, 7)) # 107
println(consume(foo, 9)) # 109
有了這樣的特性就容易實作多工 (multitasking),當然也可以決定task的排程跟優先權,也就成為了一個作業系統的核心
使用task與function不同的點在於: