【问题标题】:concurrency | goroutines | golang | buffered reader并发 |协程 |戈朗 |缓冲阅读器
【发布时间】:2017-04-21 02:51:56
【问题描述】:

相信我要么误解了 go 例程的工作原理,要么误解了缓冲阅读器的工作原理,或者两者兼而有之。

期望异步执行 goroutine(带有 for 循环的缓冲读取器读取缓冲区,等待来自服务器的消息)

尝试METHOD A在客户端拨打服务器之前调用go xyz();所以xyz() 创建缓冲区并开始在后台读取。然后,客户端拨打服务器;服务器发回消息;客户端正在读取缓冲区,因此它获取消息并打印到控制台

实际发生的情况 客户端将消息发送到服务器,但在读取可能来自服务器的回复时不会在缓冲区中获取任何内容;所以它同时运行,因为我知道 for 循环没有停止,但它让下一行代码执行(客户端向服务器发送消息)。

但是当 METHOD B 我不是同时调用xyz() 并且在客户端拨打服务器之后,所有事情都按预期工作。客户端从服务器获取消息并打印到控制台。


方法A,我们有顺序:

//////////// 步骤 1 和 2 在由 go xyz() 调用的 goroutine 中

  1. 创建缓冲阅读器
  2. for循环——从服务器读取消息缓冲区——打印出来
  3. 客户端拨打服务器

    go xyz(conn, p)

    fmt.Fprintf(conn, "Give me a hash to work on ...")


方法B,我们有顺序:

//////////// 步骤 2 和 3 在由 xyz() 调用的 goroutine 中

  1. 客户端拨打服务器
  2. 创建缓冲阅读器
  3. for循环——从服务器读取消息的缓冲区——打印出来

    fmt.Fprintf(conn, "Give me a hash to work on ...")

    xyz(conn, p)




client.go

package main
import (
    "fmt"
    "net"
    "bufio"
)

func xyz(conn net.Conn, p []byte) {
  rd := bufio.NewReader(conn)
  for {
    _, err := rd.Read(p)
    if err == nil {
      fmt.Printf("SERVER : %s\n", p)
    } else {
        fmt.Printf("Some error %v\n", err)
    }
  }
}

func main() {
    p :=  make([]byte, 2048)
    conn, err := net.Dial("udp", "127.0.0.1:1234")
    if err != nil {
        fmt.Printf("Some error %v", err)
        return
    }

    go xyz(conn, p)
    fmt.Fprintf(conn, "Give me a hash to work on ...")
}

server.go

package main
import (
    "fmt"
    "net"
)


func sendResponse(conn *net.UDPConn, addr *net.UDPAddr, hash string) {
    _,err := conn.WriteToUDP([]byte("Hello, here is the hash  - " + hash), addr)
    if err != nil {
        fmt.Printf("Couldn't send response %v", err)
    }
}


func main() {
    hash := "36";
    p := make([]byte, 2048)
    addr := net.UDPAddr{
        Port: 1234,
        IP: net.ParseIP("127.0.0.1"),
    }
    ser, err := net.ListenUDP("udp", &addr)
    if err != nil {
        fmt.Printf("Some error %v\n", err)
        return
    }
    for {
        _, remoteaddr, err := ser.ReadFromUDP(p)
        fmt.Printf("CLIENT : %v : %s\n", remoteaddr, p)
        if err !=  nil {
            fmt.Printf("Some error  %v", err)
            continue
        }
        go sendResponse(ser, remoteaddr, hash)
    }
}

【问题讨论】:

    标签: go concurrency udp bufferedreader


    【解决方案1】:

    The Go Programming Language Specification

    Go statements

    “go”语句开始执行函数调用作为 独立的并发控制线程,或 goroutine,在 相同的地址空间。

    ... 与常规调用不同,程序执行不等待 调用的函数来完成。

    client.go 启动 goroutine xyz,然后继续到终止程序的 main 函数的末尾。该程序不会等待xyz goroutine 运行或完成。

    【讨论】:

    • 所以你的意思是缓冲的阅读器在客户端从服务器接收到消息之前没有时间启动?
    • 我在 goroutine 之后和向服务器发送消息之前尝试了time.Sleep(2000)。还是不行。
    • @MattClendenen:我是说xyxmain 结束之前并没有走多远,程序也因此终止了xyx
    • time.Sleep(5000) 在客户端向服务器发送消息后使其工作。你是对的,需要时间来阅读/输出。
    • @MattClendenen:Duration 表示两个瞬间之间经过的时间,以 int64 纳秒计数。你睡了 2000 纳秒。尝试更长的时间:time.Sleep(60*time.Second).
    猜你喜欢
    • 2017-11-02
    • 2023-03-28
    • 1970-01-01
    • 2017-09-23
    • 1970-01-01
    • 2011-10-23
    • 2023-03-23
    • 2020-10-24
    • 2015-02-06
    相关资源
    最近更新 更多