Go语言并发范式之future模式详解

 更新时间:2023年06月15日 10:46:06   作者:242030  
编程中经常遇到在一个流程中需要调用多个子调用的情况,此时就可以使用Go并发编程中的future模式,下面小编就来和大家聊聊future模式的具体使用,需要的可以参考一下

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

编程中经常遇到在一个流程中需要调用多个子调用的情况,这些子调用相互之间没有依赖,如果串行地调用,则耗时会很长,此时可以使用Go并发编程中的future模式。

future模式的基本工作原理:

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

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

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

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

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

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

程序输出

result from select * from table;

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

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

2、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 <- result
	defer close(futureTask.res)
	return
}

(3)、测试代码

package main
import (
	"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 <- result
	defer 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 main
import (
	"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 <- result
	defer 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)
}

到此这篇关于Go语言并发范式之future模式详解的文章就介绍到这了,更多相关Go future模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang之如何读取文件内容

    Golang之如何读取文件内容

    这篇文章主要介绍了Golang之如何读取文件内容问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • 分布式架构在Go语言网站的应用

    分布式架构在Go语言网站的应用

    分布式架构是目前应对高流量、高并发的重要解决方案,分布式架构的核心思想是分而治之,将单台服务器的资源划分为多台服务器进行协同完成,分布式架构应用于Go语言网站中既能提升服务速度,又能降低了服务器宕机的风险
    2024-01-01
  • go mode tidy出现报错go: warning: “all“ matched no packages的解决方法

    go mode tidy出现报错go: warning: “all“ matched no package

    使用go的时候我们一般都会使用go mode管理,下面这篇文章主要给大家介绍了关于go mode tidy出现报错go: warning: “all“ matched no packages的解决方法,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • 10个现代网站开发必备的Go软件包工具盘点

    10个现代网站开发必备的Go软件包工具盘点

    这篇文章主要为大家介绍了10个现代网站开发必备的Go软件包,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • goland安装1.7版本报错Unpacked SDK is corrupted解决

    goland安装1.7版本报错Unpacked SDK is corrupted解决

    这篇文章主要为大家介绍了goland安装1.7版本报错Unpacked SDK is corrupted解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • golang实现单点登录系统(go-sso)

    golang实现单点登录系统(go-sso)

    这篇文章主要介绍了golang实现单点登录系统(go-sso),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • Go中匿名结构体的使用技巧

    Go中匿名结构体的使用技巧

    这篇文章主要给大家分享一个使用匿名结构体,提升Go编程效率的小技巧,没什么技术深度,属于在日常写代码过程中积累下来的一个提升自己编程效率的小经验
    2023-08-08
  • Go处理json数据方法详解(Marshal,UnMarshal)

    Go处理json数据方法详解(Marshal,UnMarshal)

    这篇文章主要介绍了Go处理json数据的方法详解,Marshal(),UnMarshal(),需要的朋友可以参考下
    2022-04-04
  • Golang实现密码加密的示例详解

    Golang实现密码加密的示例详解

    数据库在存储密码时,不能明文存储,需要加密后存储,而Golang中的加密算法有很多种,下面小编就来通过简单的示例和大家简单聊聊吧
    2023-07-07
  • 一文理解Goland协程调度器scheduler的实现

    一文理解Goland协程调度器scheduler的实现

    本文主要介绍了Goland协程调度器scheduler的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06

最新评论