前言
Channel 是 Golang 一个非常重要的言语特性,熟练的运用 channel 能够让咱们在并发编程中如虎添翼,本文将介绍一个根据 Golang 原生 channel 实现的 channel 扩展 PHOS,通过运用 PHOS 能够让咱们对传入 channel 的数据进行特定的处理,一起 PHOS 也具有非常丰富的装备选项,咱们能够根据不同需求对 PHOS 进行定制运用。
什么是 PHOS ?
PHOS 是一个具有内置处理器和多样化选项的 Golang Channel 扩展。
装置
留意:在装置之前,确保你运用的 Golang 版别支撑泛型(Go >= 1.18)
履行以下指令装置 PHOS:
go get github.com/B1NARY-GR0UP/phos
快速开端
在以下示例中,咱们首先界说了一个咱们自己的 PHOS 内置处理器,然后通过创立一个 PHOS 实例并将这个处理器加入到 PHOS 的处理器链中,最后咱们通过传入一个数据即可得到通过处理器处理后的结果并将其打印出来,即 BINARY += -PHOS => BINARY-PHOS
。
package main
import (
"context"
"fmt"
"github.com/B1NARY-GR0UP/phos"
)
func hello(_ context.Context, data string) (string, error) {
return data + "-PHOS", nil
}
func main() {
ph := phos.New[string]()
defer close(ph.In)
// Note: You should decide which handlers you want to use once,
// otherwise multiple changes to the Handlers slice may cause data race problem
ph.Handlers = append(ph.Handlers, hello)
ph.In <- "BINARY"
res := <-ph.Out
fmt.Println(res.Data)
}
运用协助
关于创立
PHOS 是根据泛型的,咱们在通过 phos.New
方法来创立实例时即可通过设置泛型来对特定类型的数据进行处理。
而且在创立实例时你不需求像运用普通的 Channel 那样指定 Channel 的缓冲区巨细,你能够假定 PHOS 的缓冲区没有限制。
一起 PHOS 也支撑了许多的自界说选项,咱们能够在通过 phos.New
创立实例时以选项嵌入的模式进行追加,例如:
ph := phos.New[string](phos.WithZero(), phos.WithTimeout(time.Second*5))
更多支撑的选项将在之后的章节以表格的方法列出。
关于输入输出
PHOS 通过一个只读和一个只写的 Channel 来实现数据的输入输出。
-
输入
在通过
phos.New
创立出一个实例后,通过In
这个揭露的只写 Channel 即可向 PHOS 中传入数据,例如在快速开端中咱们向In
中传入了一个字符串,需求留意的是传入数据的类型应该与你创立实例时所运用的泛型类型保持一致,而且正如咱们前面提到的,你能够接近无限制的向 PHOS 中传入数据而不要指定缓冲区的巨细:ph.In <- "BINARY" ph.In <- "Hello" ph.In <- "Foo" ...
-
输出
咱们相同能够通过
Out
这个揭露的只读 Channel 来读取通过 PHOS 处理后的数据,需求留意的是,Out
输出的值被封装为Result
类型:-
Data
字段是处理后的结果,其类型也与实例的泛型类型相匹配; -
OK
字段与咱们平常从 Channel 中获取数据的第二个可选变量用法一致,能够用来判别是否能够从 Channel 读取到数据;留意:在运用 PHOS 时你不应该再运用 Out Channel 的第二个回来值而是运用 Result 的 OK 字段,因为 Out Channel 的第二个回来值将一向为 true,对其过错的运用将导致 bug。
-
Err
字段会提示一些在运用 PHOS 时会呈现的反常,例如超时反常,内部处理器处理反常,这将在下文进行论述。
// Result PHOS output result type Result[T any] struct { Data T // Note: You should use the OK of Result rather than the second return value of PHOS Out channel OK bool Err *Error }
-
关于内置处理器
内置处理器是 PHOS 最重要的特性之一,通过设置一个或多个内置处理器,PHOS 将依照顺序对每一个输入的数据顺次履行所有的内置处理器,而且咱们能够通过回来值的方法将前一个处理器处理后的结果传入下一个处理器之中继续进行处理。
一个合法的处理器函数签名如下:
func(ctx context.Context, data T) (T, error)
咱们能够通过对 PHOS 的 Handlers
揭露切片字段追加咱们自界说的处理器来结构一个处理器链,例如如下咱们结构了一个具有三个处理器的处理器链,每一个处理器将对传入的数据进行一次加一操作,终究每个传入的数据都会在加三(+1 * 3)后回来给咱们:
package main
import (
"context"
"fmt"
"github.com/B1NARY-GR0UP/phos"
)
func plusOne(_ context.Context, data int) (int, error) {
return data + 1, nil
}
func main() {
ph := phos.New[int]()
defer close(ph.In)
ph.Handlers = append(ph.Handlers, plusOne, plusOne, plusOne)
ph.In <- 1
ph.In <- 2
ph.In <- 3
res1 := <-ph.Out
res2 := <-ph.Out
res3 := <-ph.Out
fmt.Println(res1.Data) // 4
fmt.Println(res2.Data) // 5
fmt.Println(res3.Data) // 6
}
关于反常处理
PHOS 对反常进行了包装分类,主要分为三种类型:
const (
_ ErrorType = iota
TimeoutErr
HandleErr
CtxErr
)
-
超时反常
超时机制是 PHOS 的一个核心特性,它规定了内置处理器链对每个数据的最大处理时刻,假如超时则会触发超时反常,假如不装备超时反常处理器选项则会输出对应输入的初始数据,并在
Result
的Err
字段显示超时反常;假如装备了超时反常处理器,则会输出通过超时反常处理器处理后的数据。 -
内置处理器反常
假如在履行内置处理器链中的任何一个处理器产生了反常,则处理器链终止,根据是否装备了内置处理器反常处理器来决议回来的数据是最后处理过的数据仍是通过反常处理器处理后的数据,相同反常会装备在
Result
的Err
字段。 -
上下文反常
上下文反常产生在装备了
WithContext
选项后并触发后的状况,这时数据处理会立刻终止并根据是否装备了ErrDoneFunc
回来最开端的数据仍是通过反常处理器处理后的数据,相同会将反常信息展示在Result
的Err
字段。 -
零值选项
敞开零值选项后,只要产生以上任何一种反常,都将回来对应数据类型的零值,这会对装备的超时反常处理器和内置处理器反常处理器的数据处理结果进行覆盖。
装备
选项 | 默认值 | 描绘 |
---|---|---|
WithContext |
context.Background() |
设置 PHOS 的 context |
WithZero |
false |
敞开后呈现反常时将回来对应类型的零值 |
WithTimeout |
time.Second * 3 |
设置内置处理器链的超时时刻 |
WithErrHandleFunc |
nil |
设置呈现内置处理器反常时的反常处理函数 |
WithErrTimeoutFunc |
nil |
设置呈现超时反常时的反常处理函数 |
WithErrDoneFunc |
nil |
设置呈现上下文 Done 时的反常处理函数 |
总结
以上就是对 PHOS,一个具有内置处理器和多样化选项的 Golang Channel 扩展的介绍,期望他能够为你的开发供给协助或许为你供给一些思路,假如哪里写错了或许有问题欢迎谈论或许私聊指出ww
下一篇文章将对 PHOS 的规划与实现思路进行论述,假如你对 PHOS 感兴趣,欢迎 Star !!!
跋文
因为初版的 PHOS 被发现在某些场景下会呈现 data race 问题,详见 这个 issue ,目前已经修复,而且因为对部分 API 进行了修正发布了新的中版别。主要调整的 API 为用户增加处理器 Handler 部分的方法,新的版别供给了 Append
,Remove
,Len
等方法而禁止用户对 PHOS 的 Handler 切片直接进行修正。整体运用方法根本不变,详情能够参阅 PHOS Readme。
参阅列表
- github.com/B1NARY-GR0U…