Let‘s Go —— Go语言开发之旅(六)

简介

ReactiveX是Reactive Extensions的缩写,一般简写为Rx,最初是LINQ的一个扩展,由微软的架构师Erik Meijer领导的团队开发,在2012年11月开源,Rx是一个编程模型,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流,Rx库支持.NET、JavaScript和C++,Rx近几年越来越流行了,现在已经支持几乎全部的流行编程语言了,Rx的大部分语言库由ReactiveX这个组织负责维护,比较流行的有RxJava/RxJS/Rx.NET,社区网站是 reactivex.io。

为什么要重写

Go 语言的 RxGo 看上去就像 go 入门不久的人写的,很怪异。 但 RxJava 库写的很好。pmlpml/RxGo 模仿 Java 版写了 Go 版本新实现,已基本实现了 Creating Observables 和 Transforming Observables 两类算子。

修改、改进 RxGo 包

阅读 ReactiveX 文档。请在 pmlpml/RxGo 基础上,

  • 修改、改进它的实现
  • 或添加一组新的操作,如 filtering
  • 该库的基本组成:
    • rxgo.go 给出了基础类型、抽象定义、框架实现、Debug工具等
    • generators.go 给出了 sourceOperater 的通用实现和具体函数实现
    • transforms.go 给出了 transOperater 的通用实现和具体函数实现

FilteringOperator

FilteringOperator结构体实现

type filteringOperator struct {
	opFunc func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool)
}

Filtering Observables

  • Debounce — only emit an item from an Observable if a particular timespan has passed without it emitting another item
  • Distinct — suppress duplicate items emitted by an Observable
  • ElementAt — emit only item n emitted by an Observable
  • Filter — emit only those items from an Observable that pass a predicate test
  • Find — emit the first item passing a predicate then complete
  • First — emit only the first item or the first item that meets a condition, from an Observable
  • IgnoreElements — do not emit any items from an Observable but mirror its termination notification
  • Last — emit only the last item emitted by an Observable
  • Sample — emit the most recent item emitted by an Observable within periodic time intervals
  • Skip — suppress the first n items emitted by an Observable
  • SkipLast — suppress the last n items emitted by an Observable
  • Take — emit only the first n items emitted by an Observable
  • TakeLast — emit only the last n items emitted by an Observable

Debounce

only emit an item from an Observable if a particular timespan has passed without it emitting another item
在这里插入图片描述

func (parent *Observable) Debounce(timespan time.Duration) (o *Observable) {
	o = parent.newFilterObservable("debounce")
	o.flip_accept_error = true
	o.flip_sup_ctx = true
	count := 0
	o.operator = filteringOperator{
		opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {
			count++
			go func() {
				tempCount := count
				time.Sleep(timespan)
				select {
				case <-ctx.Done():
					return
				default:
					if tempCount == count {
						o.sendToFlow(ctx, item.Interface(), out)
					}
				}
			}()
			return false
		},
	}
	return o
}

Distinct

suppress duplicate items emitted by an Observable
在这里插入图片描述

func (parent *Observable) Distinct() (o *Observable) {
	o = parent.newFilterObservable("distinct")
	o.flip_accept_error = true
	o.flip_sup_ctx = true
	m := map[string]bool{}
	o.operator = filteringOperator{
		opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {
			itemStr := fmt.Sprintf("%v", item)
			if _, ok := m[itemStr]; !ok {
				m[itemStr] = true
				o.sendToFlow(ctx, item.Interface(), out)
			}
			return false
		},
	}
	return o
}

ElementAt

emit only item n emitted by an Observable
在这里插入图片描述

func (parent *Observable) ElementAt(num int) (o *Observable) {
	o = parent.newFilterObservable("elementAt.n")
	o.flip_accept_error = true
	o.flip_sup_ctx = true
	count := 0
	o.operator = filteringOperator{
		opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {
			if count == num {
				o.sendToFlow(ctx, item.Interface(), out)
				return true
			}
			count++
			return false
		},
	}

	return o
}

First

emit only the first item or the first item that meets a condition, from an Observable
在这里插入图片描述

func (parent *Observable) First() (o *Observable) {
	o = parent.newFilterObservable("first")
	o.flip_accept_error = true
	o.flip_sup_ctx = true
	o.operator = filteringOperator{
		opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {
			o.sendToFlow(ctx, item.Interface(), out)
			return true
		},
	}
	return o
}

IgnoreElements

do not emit any items from an Observable but mirror its termination notification
在这里插入图片描述

func (parent *Observable) IgnoreElements() (o *Observable) {
	o = parent.newFilterObservable("ignoreElements")
	o.flip_accept_error = true
	o.flip_sup_ctx = true
	o.operator = filteringOperator{
		opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {
			return false
		},
	}
	return o
}

Last

emit only the last item emitted by an Observable
在这里插入图片描述

func (parent *Observable) Last() (o *Observable) {
	o = parent.newFilterObservable("last")
	o.flip_accept_error = true
	o.flip_sup_ctx = true
	o.operator = filteringOperator{
		opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {
			o.flip = append([]interface{}{}, item.Interface())
			return false
		},
	}
	return o
}

Sample

emit the most recent item emitted by an Observable within periodic time intervals
在这里插入图片描述

func (parent *Observable) Sample(sample chan interface{}) (o *Observable) {
	o = parent.newFilterObservable("sample")
	o.flip_accept_error = true
	o.flip_sup_ctx = true
	var latest interface{} = nil
	o.operator = filteringOperator{
		opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {
			latest = item.Interface()
			go func() {
				tempEnd := true
				for tempEnd {
					select {
					case <-ctx.Done():
						tempEnd = true
					case <-sample:
						if latest != nil {
							if o.sendToFlow(ctx, latest, out) {
								tempEnd = false
							}
							latest = nil
						}
					}
				}
			}()
			return false
		},
	}
	return o
}

Skip

suppress the first n items emitted by an Observable
在这里插入图片描述

func (parent *Observable) Skip(num int) (o *Observable) {
	o = parent.newFilterObservable("skip.n")
	o.flip_accept_error = true
	o.flip_sup_ctx = true
	count := 0
	o.operator = filteringOperator{
		opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {
			count++
			if count > num {
				o.sendToFlow(ctx, item.Interface(), out)
			}
			return false
		},
	}

	return o
}

SkipLast

suppress the last n items emitted by an Observable

func (parent *Observable) SkipLast(num int) (o *Observable) {
	o = parent.newFilterObservable("skipLast.n")
	o.flip_accept_error = true
	o.flip_sup_ctx = true
	count := 0
	var lasts []interface{}
	o.operator = filteringOperator{
		opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {
			if count == num {
				o.sendToFlow(ctx, lasts[0], out)
				lasts = lasts[1:]
			} else {
				count++
			}
			lasts = append(lasts, item.Interface())
			return false
		},
	}

	return o
}

Take

emit only the first n items emitted by an Observable
在这里插入图片描述

func (parent *Observable) Take(num int) (o *Observable) {
	o = parent.newFilterObservable("take.n")
	o.flip_accept_error = true
	o.flip_sup_ctx = true
	count := 0
	o.operator = filteringOperator{
		opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {
			count++
			if count > num {
				return true
			}
			o.sendToFlow(ctx, item.Interface(), out)
			return false
		},
	}

	return o
}

TakeLast

emit only the last n items emitted by an Observable
在这里插入图片描述

func (parent *Observable) TakeLast(num int) (o *Observable) {
	o = parent.newFilterObservable("takeLast.n")
	o.flip_accept_error = true
	o.flip_sup_ctx = true
	count := 0
	var lasts []interface{}
	o.operator = filteringOperator{
		opFunc: func(ctx context.Context, o *Observable, item reflect.Value, out chan interface{}) (end bool) {
			count++
			if count <= num {
				lasts = append(lasts, item.Interface())
			} else {
				lasts = lasts[1:]
				lasts = append(lasts, item.Interface())
			}
			o.flip = lasts
			return false
		},
	}

	return o
}

单元测试

完成filtering相关功能后,编写单元测试测试函数功能

func TestDistinct(t *testing.T) {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).Distinct().Subscribe(func(x int) {
		fmt.Print(x)
	})
	fmt.Println()
	//Output:123456789
}

func TestElementAt(t *testing.T) {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).ElementAt(5).Subscribe(func(x int) {
		fmt.Print(x)
	})
	fmt.Println()
	//Output:6
}

func TestFirst(t *testing.T) {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).First().Subscribe(func(x int) {
		fmt.Print(x)
	})
	fmt.Println()
	//Output:1
}

func TestIgnoreElements(t *testing.T) {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).IgnoreElements().Subscribe(func(x int) {
		fmt.Print(x)
	})
	fmt.Println()
	//Output:
}

func TestLast(t *testing.T) {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).Last().Subscribe(func(x int) {
		fmt.Print(x)
	})
	fmt.Println()
	//Output:9
}

func TestSample(t *testing.T) {
	observableP := make(chan interface{})
	go func() {
		Just(1, 2, 3, 4, 5).Map(func(x int) int {
			switch x {
			case 1:
				time.Sleep(0 * time.Millisecond)
			case 2:
				time.Sleep(1 * time.Millisecond)
			case 3:
				time.Sleep(2 * time.Millisecond)
			case 4:
				time.Sleep(2 * time.Millisecond)
			default:
				time.Sleep(2 * time.Millisecond)
			}
			return x
		}).Subscribe(func(x int) {
			observableP <- x
		})
	}()
	Just(1, 2, 3, 4, 5).Map(func(x int) int {
		time.Sleep(2 * time.Millisecond)
		return x
	}).Sample(observableP).Subscribe(func(x int) {
		fmt.Print(x)
	})
	fmt.Println()
	//Output:123
}

func TestSkip(t *testing.T) {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).Skip(2).Subscribe(func(x int) {
		fmt.Print(x)
	})
	fmt.Println()
	//Output:3456789
}

func TestSkipLast(t *testing.T) {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).SkipLast(2).Subscribe(func(x int) {
		fmt.Print(x)
	})
	fmt.Println()
	//Output:1234567
}

func TestTake(t *testing.T) {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).Take(4).Subscribe(func(x int) {
		fmt.Print(x)
	})
	fmt.Println()
	//Output:1234
}

func TestTakeLast(t *testing.T) {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).TakeLast(4).Subscribe(func(x int) {
		fmt.Print(x)
	})
	fmt.Println()
	//Output:6789
}

func TestDebounce(t *testing.T) {
	Just(0, 1, 2, 3, 4, 5).Map(func(x int) int {
		switch x {
		case 0:
			time.Sleep(0 * time.Millisecond)
		case 1:
			time.Sleep(1 * time.Millisecond)
		case 2:
			time.Sleep(2 * time.Millisecond)
		case 3:
			time.Sleep(3 * time.Millisecond)
		case 4:
			time.Sleep(4 * time.Millisecond)
		default:
			time.Sleep(1 * time.Millisecond)
		}
		return x
	}).Debounce(2 * time.Millisecond).Subscribe(func(x int) {
		fmt.Print(x)
	})
	fmt.Println()
	//Output:12
}

运行单元测试成功

在这里插入图片描述

基准测试

func BenchmarkDistinct(b *testing.B) {
    for i := 0; i < b.N; i++ {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).Distinct().Subscribe(func(x int) {})
    }
}

func BenchmarkElementAt(b *testing.B) {
    for i := 0; i < b.N; i++ {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).ElementAt(5).Subscribe(func(x int) {})
    }
}

func BenchmarkFirst(b *testing.B) {
    for i := 0; i < b.N; i++ {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).First().Subscribe(func(x int) {})
    }
}

func BenchmarkIgnoreElements(b *testing.B) {
    for i := 0; i < b.N; i++ {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).IgnoreElements().Subscribe(func(x int) {})
    }
}

func BenchmarkLast(b *testing.B) {
    for i := 0; i < b.N; i++ {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).Last().Subscribe(func(x int) {})
    }
}

func BenchmarkSkip(b *testing.B) {
    for i := 0; i < b.N; i++ {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).Skip(2).Subscribe(func(x int) {})
    }
}

func BenchmarkSkipLast(b *testing.B) {
    for i := 0; i < b.N; i++ {
    	for i := 0; i < b.N; i++ {
	    Just(1, 2, 3, 4, 5, 6, 7, 8, 9).SkipLast(2).Subscribe(func(x int) {})
    	}
    }
}

func BenchmarkTake(b *testing.B) {
    for i := 0; i < b.N; i++ {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).Take(4).Subscribe(func(x int) {})
    }
}



func BenchmarkTakeLast(b *testing.B) {
    for i := 0; i < b.N; i++ {
	Just(1, 2, 3, 4, 5, 6, 7, 8, 9).TakeLast(4).Subscribe(func(x int) {})
    }
}

/*
 *
func BenchmarkSample(b *testing.B) {
    for i := 0; i < b.N; i++ {
	observableP := make(chan interface{})
	go func() {
		Just(1, 2, 3, 4, 5).Map(func(x int) int {
			switch x {
			case 1:
				time.Sleep(0 * time.Millisecond)
			case 2:
				time.Sleep(1 * time.Millisecond)
			case 3:
				time.Sleep(2 * time.Millisecond)
			case 4:
				time.Sleep(2 * time.Millisecond)
			default:
				time.Sleep(2 * time.Millisecond)
			}
			return x
		}).Subscribe(func(x int) {
			observableP <- x
		})
	}()
	Just(1, 2, 3, 4, 5).Map(func(x int) int {
		time.Sleep(2 * time.Millisecond)
		return x
	}).Sample(observableP).Subscribe(func(x int) {})
    }
}

func BenchmarkDebounce(b *testing.B) {
    for i := 0; i < b.N; i++ {
	Just(0, 1, 2, 3, 4, 5).Map(func(x int) int {
		switch x {
		case 0:
			time.Sleep(0 * time.Millisecond)
		case 1:
			time.Sleep(1 * time.Millisecond)
		case 2:
			time.Sleep(2 * time.Millisecond)
		case 3:
			time.Sleep(3 * time.Millisecond)
		case 4:
			time.Sleep(4 * time.Millisecond)
		default:
			time.Sleep(1 * time.Millisecond)
		}
		return x
	}).Debounce(2 * time.Millisecond).Subscribe(func(x int) {
})
    }
}

*/

运行基准测试成功

在这里插入图片描述

参考资料

修改、改进 RxGo 包
RxGo包 filtering

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值