我试图理解 golang 架构以及“轻量级线程”的含义。我已经读过一些内容,但想提出问题来澄清它。
如果我说幕后的“go”关键字只是将以下函数放入内部线程池的队列中,但对于用户来说,它看起来像是创建线程,我是对的吗?
我正在尝试在 /go 中构建客户端服务器应用程序。
服务器只有一个实例,其中包含任务列表,这些任务只是字符串数据。服务器维护任务映射及其分配状态。
另一方面,客户端可以有多个实例,并向服务器请求任务。当分配任务时,服务器将分配状态更新为 true。
客户端和服务器之间的通信是通过go rpc进行的。
为了模拟多个客户端,我在单个应用程序中启动多个 go 例程,向服务器发出请求。
package main
import (
"fmt"
"log"
"net/http"
"net/rpc"
"sync"
)
type Container struct {
mu sync.Mutex
list map[string]bool
}
var ListOfTasks Container
func (c *Container) UpdateList() string {
var t string
ListOfTasks.mu.Lock()
defer ListOfTasks.mu.Unlock()
for k, v := range c.list {
if !v {
c.list[k] = true
fmt.Println("Task Name", k)
return k
}
}
return t
}
// RPC Code
type RPCServer struct{}
type …Run Code Online (Sandbox Code Playgroud) package main
import "fmt"
func square(numbers chan int, squares chan int) {
for n := range numbers {
squares <- n * n
}
close(squares)
}
func main() {
numbers := make(chan int)
squares := make(chan int)
go square(numbers, squares)
for i := 0; i < 10; i++ {
numbers <- i
}
close(numbers)
for s := range squares {
fmt.Println(s)
}
}
Run Code Online (Sandbox Code Playgroud)
我的意思是,我知道要使这段代码正常工作,应该将数字发送到numbers单独的 goroutine 中的通道,例如:
go func() {
for i := 0; i < 10; i++ { …Run Code Online (Sandbox Code Playgroud) 我有一个永远循环,它有一个 Timer 变量,在一段时间后执行一个函数。
package main
import (
fmt "fmt"
"time"
)
func exe() {
fmt.Println("10-seconds-of-time-is-done")
}
func t() {
var timerCheck *time.Timer
fmt.Println("here's the timerCheck", timerCheck)
for {
timerCheck = time.AfterFunc(10*time.Second, func() { exe() })
fmt.Println("exiting-from-function-t")
return
}
}
func main() {
t()
fmt.Println("waiting-inside-main")
time.Sleep(20 * time.Second)
}
Run Code Online (Sandbox Code Playgroud)
这是输出。我不明白该函数t()立即返回,而是在 10 秒后timerCheck执行其exe()函数。
here's the timerCheck <nil>
exiting-from-function-t
waiting-inside-main
10-seconds-of-time-is-done
Run Code Online (Sandbox Code Playgroud)
这怎么可能?在标准库中,关于AfterFunc
// AfterFunc waits for the duration to elapse and then calls f
// in …Run Code Online (Sandbox Code Playgroud) 我有一个缓冲的通道,可以通过多个(在此示例中为4)go例程读取。
queue := make(chan string, 10000) // a large buffered channel
Run Code Online (Sandbox Code Playgroud)
每个go例程都会检查通道中可用的元素数量,并对所有元素进行处理。
for i :=0; i< 4; i++{ // spun 4 go routines
go func() {
for {
for elem := range queue {
// do something with the elem from the channel
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
多个go例程会在读取时发生冲突吗?换句话说,不同的go例程可以在通道中捕获相同的元素,还是一个go例程正在读取缓冲区,而另一个go例程已经读取并处理了某些元素?如何在阅读一个go例程的同时阻止其他go例程读取?
我有一个如下所示的程序。它启动NumberOfCPUs-1goroutines 并且在每个 goroutine 中只更新全局变量x。输出是x = 0。
func main() {
var x int
threads := runtime.GOMAXPROCS(0)-1
for i := 0; i < threads; i++ {
go func() {
for {
x++
}
}()
}
time.Sleep(time.Second)
fmt.Println("x =", x)
}
Run Code Online (Sandbox Code Playgroud)
如果我稍微改变一下程序,就像这样:
func main() {
var x int
threads := runtime.GOMAXPROCS(0)
for i := 0; i < threads; i++ {
go func() {
for {
x++
time.Sleep(0)
}
}()
}
time.Sleep(time.Second)
fmt.Println("x =", x)
}
Run Code Online (Sandbox Code Playgroud)
x 将是一些随机的大值。 …
我正在尝试使用Go自动化我的侦察工具.到目前为止,我可以在kali(Nikto/whois)中运行两个基本工具.现在我希望它们并行执行,而不是等待一个函数完成.读了一下之后,我才知道这可以通过使用goroutines来实现.但我的代码似乎不起作用:
package main
import (
"log"
"os/exec"
"os"
"fmt"
)
var url string
func nikto(){
cmd := exec.Command("nikto","-h",url)
cmd.Stdout = os.Stdout
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
}
func whois() {
cmd := exec.Command("whois","google.co")
cmd.Stdout = os.Stdout
err := cmd.Run()
if err !=nil {
log.Fatal(err)
}
}
func main(){
fmt.Printf("Please input URL")
fmt.Scanln(&url)
nikto()
go whois()
}
Run Code Online (Sandbox Code Playgroud)
我明白在这里,go whois()会一直执行main(),但我仍然看不到它们都执行并行.
我正在尝试了解goroutine。在下面的示例中,为什么1)-4)表现不同?参见https://play.golang.org/p/_XXZe47W53v
package main
import (
"fmt"
"time"
)
func send(x int, ch chan int) {ch<-x}
func read(ch chan int) {fmt.Println(<-ch)}
func main() {
ch := make(chan int)
go read(ch) // 1) works
go send(1,ch) // -> 1
// go fmt.Println(<-ch) // 2) fatal error: all goroutines are asleep - deadlock!
// go send(1,ch) // isn't this the same as the above ?
// go send(1,ch) // 3) works
// go fmt.Println(<-ch) // -> 1
// go fmt.Println(<-ch) // 4) …Run Code Online (Sandbox Code Playgroud) 如果我定义了一个没有缓冲区的通道并向其中写入一个数据,它会立即阻塞吗(以便内核将寻找从该通道读取的另一个不受阻塞的goroutine),或者它会继续执行并在下次尝试某些代码时阻塞在尚未读取该通道时再次写入该通道?
以下是我编写的用于研究此问题的两段代码。
代码1:
package main
import "fmt"
func main() {
c := make(chan int)
go func() {
for i := 0;i < 3; i++ {
c <- i
fmt.Printf("number %v inserted into channel\n", i)
}
}()
for i := 0; i < 3; i++ {
fmt.Printf("number poped from channel %v\n", <-c)
}
}
Run Code Online (Sandbox Code Playgroud)
输出是这样的:
number 0 inserted into channel
number poped from channel 0
number poped from channel 1
number 1 inserted into channel
number 2 inserted into channel
number …Run Code Online (Sandbox Code Playgroud) 我在想mutex在 Go 中会锁定数据并且不允许任何其他人读/写,goroutine除非拳头goroutine释放锁。看来我的理解是错误的。阻止其他人读/写的唯一方法goroutine是调用lock其他goroutines人。这将确保critical section只有一个访问goroutine。
所以,我希望这段代码有一个死锁:
package main
import(
"fmt"
"sync"
)
type myMap struct {
m map[string]string
mutex sync.Mutex
}
func main() {
done := make(chan bool)
ch := make(chan bool)
myM := &myMap{
m: make(map[string]string),
}
go func() {
myM.mutex.Lock()
myM.m["x"] = "i"
fmt.Println("Locked. Won't release the Lock")
ch <- true
}()
go func() {
<- ch
fmt.Println("Trying to write to …Run Code Online (Sandbox Code Playgroud)