关键词:
【中文标题】如何在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中模拟并发请求,自然是很方便的,只要多开几个线程,发起请求就好了。但是,这种请求... 查看详情