Go语言并发范式-future模式

news/2025/2/13 0:39:58/

1、Go语言并发范式-future模式

编程中经常遇到在一个流程中需要调用多个子调用的情况,这些子调用相互之间没有依赖,如果串行地调用,则耗

时会很长,此时可以使用Go并发编程中的future模式。

future模式的基本工作原理:

(1)、使用chan作为函数参数。

(2)、启动goroutine调用函数。

(3)、通过chan传入参数。

(4)、做其他可以并行处理的事情。

(5)、通过chan异步获取结果。

package mainimport ("fmt""time"
)// 一个查询结构体
// 这里的sql和result是一个简单的抽象,具体的应用,可能是更复杂的数据类型
type query struct {//参数Channelsql chan string//结果Channelresult chan string
}//执行Query
func execQuery(q query) {//启动协程go func() {//获取输入sql := <-q.sql//访问数据库//输出结果通道q.result <- "result from " + sql}()
}func main() {//初始化Queryq := query{make(chan string, 1), make(chan string, 1)}//执行Query,注意执行的时候无需准备参数go execQuery(q)//准备参数q.sql <- "select * from table;"//do otherthingstime.Sleep(1 * time.Second)//获取结果fmt.Println(<-q.result)
}
# 程序输出
result from select * from table;

future最大的好处是将函数的同步调用转换为异步调用,适用于一个交易需要多个子调用且这些子调用没有依赖

的场景。实际情况可能比上面示例复杂得多,要考虑错误和异常的处理,读者着重体验这种思想,而不是细节。

Future模式的实现步骤:

(1)、构建结构体FutureTask

这里我们将要做的事情抽象成任务,对于每个任务我们可能需要传递参数过去,并且我们还需要得到这个任务的

执行结果,为此,我们创建两个channel,一个用于传递参数,一个用于保存结果。(具体还需要什么其他的参

数可以根据具体业务进行设计)。

// FutureTask 在并发执行时用于传递参数和保存返回的结果
type FutureTask struct {// 用于传递参数args chan interface{}// 实际业务中可能还有很多其他的数据// 用于保存结果res chan interface{}
}

(2)、创建goroutine执行future的方法

在创建好FutureTask之后,需要开启goroutine去执行,为此需要创建一个执行FutureTask的方法:

// execFutureTask 用于开启一个Future模式的线程
func execFutureTask(futureTask *FutureTask) {// 读取传入的参数fmt.Println("goroutine读取到的参数:", <-futureTask.args)// 这里可以执行具体的业务逻辑result := "执行完业务逻辑后得到的结果"// 将结果进行保存futureTask.res <- resultdefer close(futureTask.res)return
}

(3)、测试代码

package mainimport ("fmt""time"
)// FutureTask 在并发执行时用于传递参数和保存返回的结果
type FutureTask struct {// 用于传递参数args chan interface{}// 实际业务中可能还有很多其他的数据// 用于保存结果res chan interface{}
}// execFutureTask 用于开启一个Future模式的线程
func execFutureTask(futureTask *FutureTask) {// 读取传入的参数fmt.Println("goroutine读取到的参数:", <-futureTask.args)// 这里可以执行具体的业务逻辑result := "执行完业务逻辑后得到的结果"// 将结果进行保存futureTask.res <- resultdefer close(futureTask.res)return
}func main() {// 创建一个FutureTask并开启一个goroutine去执行futureTask := FutureTask{make(chan interface{}), make(chan interface{})}go execFutureTask(&futureTask)// 向FutureTask传入参数,如果不传的话会死锁futureTask.args <- "main线程传入的参数"// 这里可以并行的去执行一些其他业务逻辑time.Sleep(1 * time.Second)// 读取线程执行的fmt.Println("主线程读取future模式下goroutine的结果:", <-futureTask.res)}

(4)、执行结果

// 程序输出
goroutine读取到的参数: main线程传入的参数
主线程读取future模式下goroutine的结果: 执行完业务逻辑后得到的结果

(5)、完整代码

package mainimport ("fmt""time"
)// FutureTask 在并发执行时用于传递参数和保存返回的结果
type FutureTask struct {// 用于传递参数args chan interface{}// 实际业务中可能还有很多其他的数据// 用于保存结果res chan interface{}
}// execFutureTask 用于开启一个Future模式的线程
func execFutureTask(futureTask *FutureTask) {// 读取传入的参数fmt.Println("goroutine读取到的参数:", <-futureTask.args)// 这里可以执行具体的业务逻辑result := "执行完业务逻辑后得到的结果"// 将结果进行保存futureTask.res <- resultdefer close(futureTask.res)return
}func main() {// 创建一个FutureTask并开启一个goroutine去执行futureTask := FutureTask{make(chan interface{}), make(chan interface{})}go execFutureTask(&futureTask)// 向FutureTask传入参数,如果不传的话会死锁futureTask.args <- "main线程传入的参数"// 这里可以并行的去执行一些其他业务逻辑time.Sleep(1 * time.Second)// 读取线程执行的fmt.Println("主线程读取future模式下goroutine的结果:", <-futureTask.res)}

http://www.ppmy.cn/news/387907.html

相关文章

如何选择到最合适的DDoS缓解服务?

DDoS缓解服务提供商的数量可能很多&#xff0c;但只有一些提供商提供高效服务的所有必要功能&#xff0c;因此如果要选择正确的 DDoS保护解决方案&#xff0c;必须考虑以下因素&#xff1a; 1.缩小风险范围 选择DDoS缓解服务的第一步&#xff0c;确定您组织的特定需求&#…

视觉SLAM十四讲——ch7实践(视觉里程计1)

视觉SLAM十四讲----ch7的实践操作及避坑 1. 实践操作前的准备工作2. 实践过程2.1 特征提取与匹配2.2 对极几何2.3 三角测量2.4 求解PnP2.5 求解ICP 3. 遇到的问题3.1 准备工作遇到的问题 1. 实践操作前的准备工作 在终端中进入ch7文件夹下&#xff0c;顺序执行以下命令进行编译…

知乎视频发布软件使用方法视频

知乎视频发布软件使用方法视频&#xff0c;知乎批量发布软件效果怎么样 #小红书视频上传#抖音seo软件#网络推广#视频营销 软件有月卡、季卡、半年卡、年卡 【其中推荐&#xff1a;百家号 哔哩哔哩B站&#xff0c;微博等软件发帖】 服务时间&#xff1a;&#xff08;8&#xf…

element UI日历组件自定义操作设置农历、阳历、节日展示、单日操作

图例&#xff1a; 自定义calendar.js,其他页面直接引入就可以 /** * 1900-2100区间内的公历、农历互转 * charset UTF-8 * Author Jea杨(JJonlineJJonline.Cn) * Time 2014-7-21 * Time 2016-8-13 Fixed 2033hex、Attribution Annals * Time 2016-9-25 Fixed lunar …

跟我volatile从表面到底层

原文来自我的博客月泉的博客 食用该篇文章&#xff0c;作者建议你最好已经提前了解过&#xff1a;JMM以及CPU缓存一致性协议还有相关的内存屏障的知识并且能够理解CPU的乱序执行&#xff0c;如果作者理解不当&#xff0c;欢迎指出。 如果本文对你有所帮助不妨给 博客的Github点…

volatile从表面到底层

该篇文章讨论的议题&#xff1a; java语义上的volatile内存屏障JVM的实现生成的汇编指令如何保障的的可见性和有序性为什么volatile不能保证复合操作的原子性 java语义上的volatile 我们从一个很常见的案例开始出发 public class Test {public static void main(String[] a…

带卷积核的神经网络的迭代次数与收敛标准的关系

制作一个带有卷积核的神经网络让这个网络向1,0收敛,y[0]向1收敛&#xff0c;y[1]向0收敛。收敛标准用δ表示,当满足条件 while(Math.abs(y[0]-1)> δ || Math.abs(y[1]-0)> δ ) 网络开始迭代&#xff0c;本文尝试了1e-3到9e-7共21个收敛标准&#xff0c;记录每个收敛…

RSA攻击持续总结

RSA攻击持续总结 RSA算法描述 1、变量涉及 明文&#xff1a;m 密文&#xff1a;c 模数&#xff1a;n 大质数&#xff1a;p&#xff0c;q 欧拉函数值&#xff1a;r 密钥&#xff1a;d&#xff0c;e 2、算法流程 随机生成两个大质数p&#xff0c;qnp*qr(p-1)*(q-1)求e&#xf…