如何在golang中顺序处理并发请求? [复制]

     2023-03-14     206

关键词:

【中文标题】如何在golang中顺序处理并发请求? [复制]【英文标题】:How to handle concurrent request sequentially in golang? [duplicate] 【发布时间】:2019-04-11 23:03:51 【问题描述】:

我是 Golang 的新手,我发现 Go 频道非常有趣。我的背景来自 JavaScript,我想在 Go 中按顺序处理并发请求,有点像 JavaScript 中的Promise.all()。我想要的只是发出一些并发运行的请求,并按照我调用它们的顺序处理返回的数据。

等效的 JavaScript 代码如下:

async function main() 
  // Assuming all db calls will return a promise
  const firstUserPromise = firstDbCall().then((res) => res);
  const secondUserPromise = secondDbCall().then((res) => res);
  const thridUserPromise = thridDbCall().then((res) => res);

  const [
    firstUserData,
    secondUserData,
    thirdUserData
  ] = await Promise.all([firstUserPromise, secondUserPromise, thirdUserPromise]);

如果您不熟悉 JavaScript,在上面的代码中,我会同时进行三个数据库调用(从第 3 行到第 5 行)。然后我在等待他们给出一些回应(从第 7 行到第 10 行)。这段代码的好处在于,当所有三个数据库调用都完成后,我将按照等待它们的顺序获得结果。 firstUserData 会收到来自firstUserPromise 的回复,secondUserData 会收到来自secondUserPromise 等等。

下面是一个假设的代码,我希望它等同于上面的 JavaScript 代码:

package main

import "fmt"

func main() 
  set = make(chan, string)
  get = make(chan, string)

  // First DB call
  go firstDbCall()
  // Second DB call
  go secondDbCall()
  // Third DB call
  go thirdDbCall()

  // How to make sending data to channels predictable
  // First data to `set` channel will send data to firstDbCall
  // Second one will `set` to secondDbCall and so on.
  set <- "userId 1"
  set <- "userId 2"
  set <- "userId 3"

  // Similarly, How to make receiving data from channels predictable
  // firstUserData will data of "userId 1", secondUserData will have
  // data of "userId 2" and so on.
  firstUserData := <-get
  secondUserData := <-get
  thirdUserData := <-get

由于从通道获取数据是不可预测的,我怎样才能让它们像 JavaScript 代码一样可预测?

【问题讨论】:

让每个 goroutine 将其结果填充到切片中自己的元素中。 @Mohammad_Aziz 关注第一条评论。它不仅说明您的问题的重复性,而且还提及您正在寻找的答案。如果这没有帮助,请在需要时回复此社区的帮助。 为什么不将函数作为参数传递给 db 调用,并在那里处理? 您关心函数的执行顺序还是关心结果处理的顺序?如果是第一个,你应该按顺序做事,没有渠道或套路。如果是第二个,则使用 WaitGroup 等待所有 goroutine 完成,让它们将结果存储在预定义的切片或数组中,并以您认为正确的任何顺序处理结果数组。 我不知道WaitGroup 以及它是如何工作的。我确实关心处理结果的顺序@MadWombat。 【参考方案1】:

Go 通道实际上只是线程安全的队列。在这种情况下,它看起来不像队列(因此​​是通道)适合您的用例。我建议查看sync.WaitGroup

package main

import "sync"

func main() 
    var (
        firstUserData, secondUserData, thirdUserData string
        wg                                           sync.WaitGroup
    )
    wg.Add(3)

    // First DB call
    go func() 
        defer wg.Done()
        firstUserData = firstDbCall()
    ()

    // Second DB call
    go func() 
        defer wg.Done()
        secondUserData = secondDbCall()
    ()

    // Third DB call
    go func() 
        defer wg.Done()
        thirdUserData = thirdDbCall()
    ()

    wg.Wait()

    println(firstUserData, secondUserData, thirdUserData)


func firstDbCall() string 
    return "UserId1"


func secondDbCall() string 
    return "UserId2"


func thirdDbCall() string 
    return "UserId3"

【讨论】:

您应该查看问题中的 cmets。此外,您的解决方案似乎并不像预期的那样。您刚刚将字符串分配到相应的 var 中。你不关心并发 goroutine 的完成顺序。 原始示例代码也不关心顺序。它是 3 个不同的函数调用。 也许你是对的。 @poy 我可以保证您的回答确实涵盖了我的解决方案。只是出于好奇,如果我关心完成订单,你会建议什么? 什么意思?想对订单做什么?【参考方案2】:

您想为此使用 go 例程和通道。如果顺序很重要,您可以使用定义大小的切片,如下所示:

package main

import "fmt"

func firstDBCall(resultSlice *[]string, doneChannel chan bool) 
    (*resultSlice)[0] = "1"
    doneChannel <- true


func secondDBCall(resultSlice *[]string, doneChannel chan bool) 
    (*resultSlice)[1] = "2"
    doneChannel <- true 


func thirdDBCall(resultSlice *[]string, doneChannel chan bool) 
    (*resultSlice)[2] = "3"
    doneChannel <- true


func main() 
    resultSlice := make([]string, 3)
    doneChannel := make(chan bool)
    go firstDBCall(&resultSlice, doneChannel)
    go secondDBCall(&resultSlice, doneChannel)
    go thirdDBCall(&resultSlice, doneChannel)

    for i := 0; i < 3; i++ 
        <-doneChannel
    
    fmt.Println(resultSlice)

这段代码使用 go 关键字同时调用三个函数。在切片填充的位置,您将首先进行数据库查询,然后再将结果填充到切片中。调用 go 例程后,我们有一个循环,它只使用通道检查所有例程是否已完成。这是有效的,因为从通道中读取是阻塞的。

另一个可能更优雅的解决方案是使用结构而不是切片。这也将允许不同类型的查询值。

【讨论】:

如何在 golang 的同一个处理程序中处理多个 POST 请求?

】如何在golang的同一个处理程序中处理多个POST请求?【英文标题】:HowtohandlemultiplePOSTrequestsinsamehandleringolang?【发布时间】:2022-01-2101:29:16【问题描述】:我要执行的signup.html文件中有两个表单。第一个表单重定向到/login,但不... 查看详情

如何在 Django 中处理并发请求?

】如何在Django中处理并发请求?【英文标题】:HowtohandlesimultaneousrequestsinDjango?【发布时间】:2020-07-2819:24:02【问题描述】:我在Django中有一个标准的基于函数的视图,它在用户单击按钮后通过POST接收一些参数,计算一些东西,... 查看详情

golang并发介绍(代码片段)

概述简而言之,所谓并发编程是指在一台处理器上“同时”处理多个任务。随着硬件的发展,并发程序变得越来越重要。Web服务器会一次处理成千上万的请求。平板电脑和手机app在渲染用户画面同时还会后台执行各种计算... 查看详情

如何在 Golang 中处理纯文本 HTTP Get 响应?

】如何在Golang中处理纯文本HTTPGet响应?【英文标题】:HowdoIhandleplaintextHTTPGetresponseinGolang?【发布时间】:2016-08-0619:16:51【问题描述】:我正在向返回纯文本响应的端点发出HTTPGET请求。如何获取纯文本响应的字符串?我的代码如... 查看详情

ios处理高并发量的http请求和数据集合的对应关系

...应数据的时间不同,会造成请求到的数据集合与发请求的顺序非一一对应,思路如下,创建可变字典NSMutableDictionary建立起请求与数据集合的对应关系。然后遍历字典,按key的顺序重新整理数据集合 查看详情

golang入门:并发(代码片段)

Golang入门(4):并发摘要并发程序指同时进行多个任务的程序,随着硬件的发展,并发程序变得越来越重要。Web服务器会一次处理成千上万的请求,这也是并发的必要性之一。Golang的并发控制比起Java来说&... 查看详情

golang高并发的理解(代码片段)

前言GO语言在WEB开发领域中的使用越来越广泛,Hired发布的《2019软件工程师状态》报告中指出,具有Go经验的候选人是迄今为止最具吸引力的。平均每位求职者会收到9份面试邀请。想学习go,最基础的就要理解go是怎么做到高并发... 查看详情

存根的 gRPC 并发

...办法修改这种行为?我知道在客户端流式传输rpc中,消息顺序是有保证的。如果我将请求A和请求B发送到同一个RPC,是否可以保证A在B开始处理之前先执行?还是它们各 查看详情

在 CodeIgniter 中处理并发请求

】在CodeIgniter中处理并发请求【英文标题】:DealingwithconcurrentrequestsinCodeIgniter【发布时间】:2015-08-1623:56:30【问题描述】:假设我使用CodeIgniter/PHP和MySQL创建了一个在线银行系统,并且有以下内容可以从我的银行账户中提取资金... 查看详情

tomcat如何同时处理多个并发请求?

】tomcat如何同时处理多个并发请求?【英文标题】:Howtomcathandlemultipleconcurrentrequestatthesametime?【发布时间】:2018-01-1912:36:48【问题描述】:它是否排队请求或处理并行中的一些请求?如果它并行处理请求,它如何返回异步响应?... 查看详情

在 golang 中如何使用切片进行复制? [关闭]

】在golang中如何使用切片进行复制?[关闭]【英文标题】:Howdoescopywithslicesworkingolang?[closed]【发布时间】:2021-09-1100:58:21【问题描述】:我有一个切片,我使用copy方法将切片复制到另一个切片,我不确定如何获得以下程序的以下... 查看详情

如何在golang中解析请求中的json? [关闭]

】如何在golang中解析请求中的json?[关闭]【英文标题】:howtoparsethejsonintherequestingolang?[closed]【发布时间】:2021-07-1108:47:48【问题描述】:数据:仅提取典型结构"logs":["points":[[30402984,1618566621000],[32146400,1618566636000]],"tags.metric":"name"... 查看详情

elasticsearch的乐观并发控制和分片管理(更新中)

...请求将被并行发送;异步的:这些复制请求到达目的地的顺序是乱的.  因此,Elasticsearch需要保证文档的旧版本不会覆盖新版本.Elasticserch通过_version字段来确保并更以正确的顺序得到执行.如果旧版本的文档 查看详情

如何保证异步请求中的正确顺序

】如何保证异步请求中的正确顺序【英文标题】:Howtoguaranteethecorrectorderinasyncrequest【发布时间】:2017-06-2007:36:50【问题描述】:我有一个使用Alamofire发出URL请求的iOS应用程序。当它们之间的时间很短时,我有时会发现请求以错... 查看详情

如何在 Golang 中间件中读取请求正文两次?

】如何在Golang中间件中读取请求正文两次?【英文标题】:HowtoreadrequestbodytwiceinGolangmiddleware?【发布时间】:2018-04-0711:11:03【问题描述】:在中间件中,我想读取请求正文以执行一些检查。然后,请求被传递到下一个中​​间件... 查看详情

如何在 Golang 中正确处理缓冲通道?

】如何在Golang中正确处理缓冲通道?【英文标题】:HowtohandlethebufferedchannelproperlyinGolang?【发布时间】:2016-11-1921:57:03【问题描述】:我有一个存储接收到的数据的通道,我想在满足以下条件之一时对其进行处理:1、通道达到其... 查看详情

golang系列文章:并发抓取网页内容(代码片段)

...抓取对应的网页内容并保存到本地磁盘,今天来记录一下如何利用并发,来抓取多个站点的网页内容。首先,我们在上一次代码的基础上稍作改造,使它能够获取多个站点的内容。下面代码中,我们首先定义好三个URL,然后逐个... 查看详情

java中如何模拟真正的并发请求?

  有时需要测试一下某个功能的并发性能,又不要想借助于其他工具,索性就自己的开发语言,来一个并发请求就最方便了。  java中模拟并发请求,自然是很方便的,只要多开几个线程,发起请求就好了。但是,这种请求... 查看详情