呼叫者将 task 交给 goroutine 执行,执行完毕後 goroutine 将 task 运行得到的结果传回呼叫者
在昨天讲解完 Thread-Per-Message Pattern 後,将 message 以 goroutine 执行後,是没办法获得回传值的,如果有此需求,可以搭配 Future Pattern
当 goroutine 运行後,呼叫者需要有一个中间物件来去取得 goroutine 未来运行的结果,golang 通常采用 channel 实作
延续推播新闻系统的情境,将新的新闻直接推播出去,除了推播系统效率要高,还需纪录推播完成的时间
相关的 code 在Github - go-design-patterns。
昨天的 code 并没办法接收到PushNews()
的回传运行完结束的时间值:
package main
import (
"fmt"
"time"
)
func PushNews(news string, startTime time.Time) time.Time {
time.Sleep(time.Duration(3 * time.Second)) //模拟推播运行的时间
fmt.Printf("%s cost %s\n", news, time.Since(startTime))
return time.Now()
}
func main() {
start := time.Now()
allNews := []string{
"中秋节来了",
"记得",
"不要户外烤肉~",
}
for _, news := range allNews {
go PushNews(news, start)
}
time.Sleep(10 * time.Second) //等待goroutine执行完毕
}
将 golang channel,实作至PushNews()
中。goroutine 运行後,将newsCh{}
先回传给呼叫者main()
,在**未来(feature)**时 goroutine 会将发送完毕的时间time.Now()
传至 channel,呼叫者main()
只需在需要时等待 channel 收到time.Now()
出现,如下:
package main
import (
"fmt"
"time"
)
func PushNews(news string, startTime time.Time) <-chan time.Time {
newsCh := make(chan time.Time)
go func() {
time.Sleep(time.Duration(3 * time.Second)) //模拟推播运行的时间
fmt.Printf("%s cost %s\n", news, time.Since(startTime))
newsCh <- time.Now()
}()
return newsCh
}
func main() {
start := time.Now()
allNews := []string{
"中秋节来了",
"记得",
"不要户外烤肉~",
}
newsChs := []<-chan time.Time{}
for _, news := range allNews {
newsChs = append(newsChs, PushNews(news, start))
}
// do something
for index, newsCh := range newsChs {
fmt.Printf("news %d is sent at %s\n", index, <-newsCh)
}
}
先透过for _, news := range allNews
将所有的新闻发送以启动 goroutine,但这边仅是启动,并取得一个中间物件 channel,等到有需要再从 channel 取得资料,甚至可以先在// do somethins
处做其他事情。
最後在for index, newsCh := range newsChs
取得 channel 的资料,如Guarded Suspension Pattern yorktodo所说,channel 会等到有资料再运行,否则等待,所以此处会等到所有<-newsCh
都接收完毕才会离开 for 回圈运行完main()
,如下:
promise 与 feature 是相似的概念,差异是:
.then(function)
的风格传送 function 给 promise 来去实作取得资料後的动作.get()
或者 golang <-channel
的方式取得资料後再呼叫处实作後续动作但两者精神相同,都是处理如何异步取得资料。
如果熟悉 javascript 的话,可以用Promise.all()
去思考此范例,如下:
const pushNews = (news, startTime) =>
new Promise((resolve) =>
setTimeout(() => {
console.log(`${news} cost ${Date.now() - startTime}`);
resolve(Date.now());
}, 3000)
);
const start = Date.now();
Promise.all(
["中秋节来了", "记得", "不要户外烤肉~"].map((news) => pushNews(news, start))
).then((allNews) =>
allNews.map((finishTimes, index) =>
console.log(`"news ${index} is sent at ${finishTimes}"`)
)
);
// do something
会发现for _, news := range allNews
与Promise.all()
相同都是在启动异步的 code,等到异步的资料都会来就以.then(function)
中的 function 来处理,由於示异步,我们也可以在程序// do something
处执行其他事情而不被 block
>>: Day 4: 人工智慧在音乐领域的应用 (AI发展史与简介 - 第一次寒冬)
在安装完Shioaji套件之後,我们就可以开始使用api的功能了。 第一步当然是要登入我们的帐户啦,...
Q1. 什麽是 Leetcode ? Leetcode 是一个线上练程序网站,收集了许多软件工程师面...
您所使用的Windows 10是否经常崩溃?您是否在Windows 10中收到档案丢失或损坏的错误?...
听听其他人对於快速面试的应对。 有被问到专案的优化方式如何,当时我答不好(冏)後来听到组员回答的很...
一、视觉化为何如此重要 终於进入到视觉化的部分了!虽然现在有很多的绘图软件,但我认为初期用pytho...