Ner*_*rve 62 concurrency go goroutine
我是golang的新手,所以请原谅这是一个非常基本的问题.下面的代码给出了编译错误,说'意外去':
x := go doSomething(arg)
func doSomething(arg int) int{
...
return my_int_value
}
Run Code Online (Sandbox Code Playgroud)
我知道,如果不正常调用函数,我可以获取返回值,而不使用goroutine.或者我可以使用频道等
我的问题是为什么不能从goroutine获取这样的返回值.
I15*_*159 68
运行goroutine(异步)并从函数中获取返回值本质上是有争议的行为.当你说go
你的意思是"异步"或甚至更简单时:"继续!不要等待功能执行完成".但是,当您将函数返回值赋给变量时,您希望在变量中包含此值.因此,当你这样做时,x := go doSomething(arg)
你会说:"继续,不要等待功能!等待等待!我需要x
在下一行的右边的var中访问返回值!"
从goroutine获取值的最自然方式是通道.通道是连接并发goroutine的管道.您可以将值从一个goroutine发送到通道,并将这些值接收到另一个goroutine或同步函数中.您可以使用select
以下方法从goroutine轻松获取不破坏并发性的值:
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(time.Second * 1)
c1 <- "one"
}()
go func() {
time.Sleep(time.Second * 2)
c2 <- "two"
}()
for i := 0; i < 2; i++ {
// Await both of these values
// simultaneously, printing each one as it arrives.
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}
Run Code Online (Sandbox Code Playgroud)
该示例取自Go By Example
Go更大程度上基于CSP理论.上面的天真描述可以用CSP来精确概述(尽管我认为它超出了问题的范围).我强烈建议您熟悉CSP理论,至少因为它是RAD.这些简短的引文给出了一个思考方向:
顾名思义,CSP允许在独立运行的组件流程方面描述系统,并且仅通过消息传递通信相互交互.
在计算机科学中,消息传递向进程发送消息,并依赖于进程和支持基础结构来选择和调用要运行的实际代码.消息传递与传统编程不同,在传统编程中,名称直接调用进程,子例程或函数.
jos*_*hlf 50
严格的答案是你可以做到这一点.这可能不是一个好主意.这里的代码可以做到这一点:
var x int
go func() {
x = doSomething()
}()
Run Code Online (Sandbox Code Playgroud)
这将产生一个新的goroutine,它将计算doSomething()
然后将结果分配给x
.问题是:你将如何使用x
原始的goroutine?您可能希望确保生成的goroutine已完成,以便您没有竞争条件.但是如果你想这样做,你需要一种与goroutine进行通信的方法,如果你有办法做到这一点,为什么不用它来发回价值呢?
go
关键字的想法是你异步运行doSomething函数,并继续当前的goroutine而不等待结果,就像在Bash shell中执行一个带有'&'的命令一样.如果你想做
x := doSomething(arg)
// Now do something with x
Run Code Online (Sandbox Code Playgroud)
那么你需要当前的goroutine来阻止,直到doSomething结束.那么,为什么不只是调用DoSomething的在当前的goroutine?还有其他选项(例如,doSomething可以将结果发布到通道,当前goroutine从中接收值)但是简单地调用doSomething并将结果分配给变量显然更简单.
这是 Go 创建者的设计选择。有大量的抽象/API 来表示异步 I/O 操作的值 - promise
、future
、async/await
、callback
、等。这些抽象/API 本质上与调度单元 -协程observable
相关- 并且这些抽象/API 决定了协程(或者更准确地说,它们所代表的异步 I/O 的返回值)可以由它们组成。
Go 选择消息传递(又名通道)作为抽象/API 来表示异步 I/O 操作的返回值。当然,goroutine 和通道为您提供了一个可组合的工具来实现异步 I/O 操作。
为什么不使用通道写入呢?
chanRes := make(chan int, 1)
go doSomething(arg, chanRes)
//blocks here or you can use some other sync mechanism (do something else) and wait
x := <- chanRes
func doSomething(arg int, out chan<- int){
...
out <- my_int_value
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
48896 次 |
最近记录: |