如何在golang中处理goroutine并从中获得响应

I have go routines called in getPosition, getStatus and rerouting for my drone currently I am invoking go GetStatus in my main function which this function has go func() which handles the event for streaming grpc and sse.

currently this is my code and i tried

func GetPositionContext(ctx context.Context, uav pb.UAVControllerClient, uavID *pb.UAVID, projectID string) {
    log.Printf("getPosition start")

    stream, err := uav.GetPosition(ctx)

    if err != nil {
        fmt.Printf("ERROR getPosition:%s", err.Error())
    }

    streamID, eventName := EventsSubscribe(projectID, uavID.Aircraft, "get_position")

    position := make(chan models.DronePosition)

    // 受信ループ開始
    go func() {
        fmt.Print("start getPosition loop")
        for {
            msg, err := stream.Recv() // msg UAVPosition
            if err == io.EOF {
                // read done.
                fmt.Print("start getPosition loop closed")
                close(position)
                return
            }
            if err != nil {
                log.Fatalf("Failed to receive getPosition : %v", err)
                close(position)
                return
            }
            // log.Printf("Position point[%s](%f, %f, %f) H:%f", uavID.Aircraft, msg.Latitude, msg.Longitude, msg.Altitude, msg.Heading)

            wayPoint := models.WaypointItem{
                Latitude:  msg.Latitude,
                Longitude: msg.Longitude,
                Altitude:  msg.Altitude,
                Heading:   msg.Heading,
            }

            dronePosition := models.DronePosition{
                Name:          uavID.Aircraft,
                ItemParameter: wayPoint,
            }

            // publish to eventgo
            publishNotif(dronePosition, streamID, eventName)
            return
        }
    }()

    startMsg := pb.UAVControllerPositionRequest{
        UavID:       uavID,
        Instruction: true,
        Interval:    2,
    }

    fmt.Print("send getPosition start")

    if err := stream.Send(&startMsg); err != nil {
        log.Fatalf("Failed to send getPosition: %v", err)
    }

    <-position

    stream.CloseSend()
    fmt.Print("end of getPosition")
}

this is the part where i call this function

go utils.GetPosition(ctx, uavService, &uavID, projectID)

I want to get the return values from go func like if everything works fine in the grpc server and no problem i should return 200 success and 500 if something failed.

for {
        time.Sleep(time.Duration(60) * time.Second)
    }

after the call i have this code which it should return every 10s a success

return c.JSON(500, failed or pass)

I expect something to return to the ui if go routines is success or failed when streaming part is working for the response not to be pending or else other api call will not work.

dsg24156
dsg24156 这是代码play.golang.org/p/NioLLk1NVds
一年多之前 回复
dovhpmnm31216
dovhpmnm31216 当前是的,我正在调用另一个go例程以传递值funcF(nint,wg*sync.WaitGroup){//延迟wg.Done()延迟wg.Done()//在此处执行结果<-n}和像通道变量这样的变量varResults=make(chanint)`
一年多之前 回复
duanjian4331
duanjian4331 您根本无法获得“来自goroutine的响应”:这根本不可能。如果您想将一个goroutine的任何结果传达给另一个goroutine,通常使用一个通道。(您应该提供一个简化的示例,因为我不知道您的代码将做什么或打算做什么)。
一年多之前 回复
dpziir0079
dpziir0079 请如果您有任何想法的帮助请
一年多之前 回复

2个回答

If you want to know if there was an error when processing the go func() inside GetPositionContext then you could do something like below. I modified all errors to bubble up rather than call log.Fatal. On a side note it might be wise to defer stream.CloseSend(), but i'm missing context and it's outside the scope of the question.

I did my best to understand the question, but if I missed something, let me know!

The code has been modified to bubble up errors within GetPositionContext directly rather than call log.Fatal. Additionally, if there is an error within the go func() it will get sent back to GetPositionContext through a channel and then returned to the caller.

func GetPositionContext(ctx context.Context, uav pb.UAVControllerClient, uavID *pb.UAVID, projectID string) error {
    log.Printf("getPosition start")

    stream, err := uav.GetPosition(ctx)

    if err != nil {
        return fmt.Errorf("ERROR getPosition: %v", err.Error())
    }

    streamID, eventName := EventsSubscribe(projectID, uavID.Aircraft, "get_position")

    errC := make(chan error)

    // 受信ループ開始
    go func() {
        fmt.Print("start getPosition loop")
        for {
            msg, err := stream.Recv() // msg UAVPosition
            if err == io.EOF {
                // read done.
                fmt.Print("start getPosition loop closed")
                close(errC)
                return
            }
            if err != nil {
                errC <- fmt.Errorf("Failed to receive getPosition : %v", err)
                return
            }
            // log.Printf("Position point[%s](%f, %f, %f) H:%f", uavID.Aircraft, msg.Latitude, msg.Longitude, msg.Altitude, msg.Heading)

            wayPoint := models.WaypointItem{
                Latitude:  msg.Latitude,
                Longitude: msg.Longitude,
                Altitude:  msg.Altitude,
                Heading:   msg.Heading,
            }

            dronePosition := models.DronePosition{
                Name:          uavID.Aircraft,
                ItemParameter: wayPoint,
            }

            // publish to eventgo
            publishNotif(dronePosition, streamID, eventName)

            // Did you mean to return here? The for loop will only ever execute one time.
            // If you didn't mean to return, then remove this close
            close(errC)
            return
        }
    }()

    startMsg := pb.UAVControllerPositionRequest{
        UavID:       uavID,
        Instruction: true,
        Interval:    2,
    }

    fmt.Print("send getPosition start")

    if err := stream.Send(&startMsg); err != nil {
        return fmt.Errorf("Failed to send getPosition: %v", err)
    }

    err = <- errC

    stream.CloseSend()
    fmt.Print("end of getPosition")
    return err
}

If you want to call this function asynchronously, but still want to know if there was an error then you could do the following.

errC := make(chan error)
go func() {
  errC <- GetPositionContext(..........)
}()
// Do some other stuff here
// Until you need the result
err := <- errC


// ... and Eventually when you want to return the success or failure as JSON
if err != nil {
  return c.JSON(500, failed)
}
return c.JSON(500, pass)
doulouli8686
doulouli8686 嗯,那也很好,但我目前的目标是当流媒体正常工作时,如果错误err!= nil,它应该返回类似200或500的值,那就是我发送错误的时间。 我现在正在修改它,但无法获得良好的结果。
一年多之前 回复
douyan1972
douyan1972 go func()中的for循环将继续循环直到遇到返回值。 在要结束循环(返回)的任何时候,请确保将错误发送到通道中或关闭通道。
一年多之前 回复
douse8732
douse8732 但是,即使结果是return,除删除close(errC)之外,是否还有可能继续运行? 这是来自grpc的流,所以我不想停止流式传输
一年多之前 回复
dongliu0823
dongliu0823 非常感谢您的回复。 我将检查并让您知道它似乎很好。
一年多之前 回复



我建议设置一个通道以接收来自go例程的事件。 在调用函数中,您可以循环监听这些事件(其中可能包含您想要的任何信息),直到go例程自身关闭,这表明失败。</ p>
</ div>

展开原文

原文

I would suggest setting up a channel to receive events from the go routine. In the calling function you can listen for these events (which can contain any information you want) in a loop until the go routine closes itself, signigying failure.

duanreng3439
duanreng3439 这是我拥有的代码play.golang.org/p/NioLLk1NVds
一年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问