ReactiveX

ReactiveX

Reactive Extensions for Async Programming

Member Since 8 years ago

Experience Points
0
follower
Lessons Completed
0
follow
Best Reply Awards
42
repos
Activity
May
19
21 hours ago
started
started time in 49 minutes ago
started
started time in 49 minutes ago
Activity icon
issue

timothy-shields issue ReactiveX/RxPY

timothy-shields
timothy-shields

Use deque in ReplaySubject

ReplaySubject currently uses a list for its internal queue. Frequently removing items from the front of a list, as is done in the _trim method, can be expensive for large lists.

The ReplaySubject could be changed to use a deque for its queue. This would give faster performance for large replay queues.

It looks like the change would involve:

  • initializing self.queue to an empty deque in init
  • replacing calls to self.queue.pop(0) in _trim with self.queue.popleft()
started
started time in 2 hours ago
Activity icon
fork

vsanthanam forked ReactiveX/RxSwift

⚡ Reactive Programming in Swift
vsanthanam MIT License Updated
fork time in 2 hours ago
started
started time in 2 hours ago
started
started time in 3 hours ago
started
started time in 3 hours ago
started
started time in 3 hours ago
Activity icon
issue

nlm issue comment ReactiveX/RxGo

nlm
nlm

Observe(rxgo.WithContext(ctx)) does not cancel observable?

Hi, I am not sure I'm using RxGo the correct way or if this use case is not supported. I have one producer and multiple consumers which want to subscribe and unsubscribe for messages. Consumers can come and go, my idea was to use the rxgo.WithContext to "cancel" consumer subscriptions, but they don't get cancelled? Is this the intended behavior or am I missing something? I've been testing out some different approaches to no success.

The test I try with his this:


func TestCtxCancel(t *testing.T) {
	ch := make(chan rxgo.Item)
	ob := rxgo.FromEventSource(ch, rxgo.WithBackPressureStrategy(rxgo.Drop))

	producerCtx, cancelProducer := context.WithCancel(context.Background())
	cancel1 := observe(1, ob)
	cancel2 := observe(2, ob)

	// Producer
	go func() {
		defer func() {
			log.Print("producer finished")
			close(ch)
		}()
		ctr := 0
		t := time.NewTicker(time.Second)
		for {
			select {
			case <-producerCtx.Done():
				return
			case <-t.C:
				ctr++
				select {
				case ch <- rxgo.Of(ctr):
				default:
					log.Printf("Send channel blocked, msg %d dropped", ctr) // This happend when I tried some other methods
				}
			}
		}
	}()

	log.Printf("Sleep 3")
	time.Sleep(time.Second * 3)
	log.Printf("Cancel Observer 1")
	cancel1()

	log.Printf("Sleep 3")
	time.Sleep(time.Second * 3)
	log.Printf("Cancel Observer 2")
	cancel2()

	log.Printf("Sleep 3")
	time.Sleep(time.Second * 3)
	log.Printf("Cancel Producer")
	cancelProducer()

	log.Printf("Sleep 1")
	time.Sleep(time.Second * 1)
}

func observe(index int, ob rxgo.Observable) context.CancelFunc {
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		for i := range ob.Observe(rxgo.WithContext(ctx)) {
			log.Printf("Observer[%d]: %v", index, i.V)
		}
		log.Printf("Observer[%d] stopped", index)
	}()
	return cancel
}

Produces the following output:

2022/01/31 08:43:59 Sleep 3
2022/01/31 08:44:00 Observer[2]: 1
2022/01/31 08:44:00 Observer[1]: 1
2022/01/31 08:44:01 Observer[2]: 2
2022/01/31 08:44:01 Observer[1]: 2
2022/01/31 08:44:02 Observer[2]: 3
2022/01/31 08:44:02 Observer[1]: 3
2022/01/31 08:44:02 Cancel Observer 1
2022/01/31 08:44:02 Sleep 3
2022/01/31 08:44:03 Observer[2]: 4
2022/01/31 08:44:03 Observer[1]: 4
2022/01/31 08:44:04 Observer[2]: 5
2022/01/31 08:44:04 Observer[1]: 5
2022/01/31 08:44:05 Observer[2]: 6
2022/01/31 08:44:05 Observer[1]: 6
2022/01/31 08:44:05 Cancel Observer 2
2022/01/31 08:44:05 Sleep 3
2022/01/31 08:44:06 Observer[2]: 7
2022/01/31 08:44:06 Observer[1]: 7
2022/01/31 08:44:07 Observer[2]: 8
2022/01/31 08:44:07 Observer[1]: 8
2022/01/31 08:44:08 Observer[2]: 9
2022/01/31 08:44:08 Observer[1]: 9
2022/01/31 08:44:08 Cancel Producer
2022/01/31 08:44:08 Sleep 1
2022/01/31 08:44:08 producer finished
2022/01/31 08:44:08 Observer[2] stopped
2022/01/31 08:44:08 Observer[1] stopped

Have I just made a mistake somewhere which leads to the observable not being cancelled? Any help is much appreciated, thanks for a great package.

nlm
nlm

According to https://github.com/ReactiveX/RxGo/blob/6d23b16c8a1c1cd758a40f4e5935cefa7999dedb/iterable_eventsource.go#L69 The current code for observing the eventSourceIterable is the following:

func (i *eventSourceIterable) Observe(opts ...Option) <-chan Item {
	option := parseOptions(append(i.opts, opts...)...)
	next := option.buildChannel()

	i.Lock()
	if i.disposed {
		close(next)
	} else {
		i.observers = append(i.observers, next)
	}
	i.Unlock()
	return next
}

It indeed seems it doesn't handle context cancellations from options. I see two options here.

Either you handle it from your code:

func observe(index int, ob rxgo.Observable) context.CancelFunc {
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		itemCh := ob.Observe(rxgo.WithContext(ctx))
	OuterLoop:
		for {
			select {
			case <-ctx.Done():
				// close(itemCh) ?
				break OuterLoop
			case i := <-itemCh:
				log.Printf("Observer[%d]: %v", index, i.V)
			}
		}
		log.Printf("Observer[%d] stopped", index)
	}()
	return cancel
}

Or maybe patching the RxGo code with something like this might do the trick (untested):

func (i *eventSourceIterable) Observe(opts ...Option) <-chan Item {
	option := parseOptions(append(i.opts, opts...)...)
	next := option.buildChannel()

	i.Lock()
	if i.disposed {
		close(next)
	} else {
		i.observers = append(i.observers, next)
		ctx := option.buildContext(context.Background())
		if ctx.Done() != nil {
			go func() {
				<-ctx.Done()
				close(next)
			}()
		}
	}
	i.Unlock()
	return next
}
started
started time in 5 hours ago
Activity icon
issue

nlm issue comment ReactiveX/RxGo

nlm
nlm

How to keep original order when using pool?

Excuse me, I want to process each element concurrently, but keep the original order in the final operation, what should I do? thanks for your help. error code:

	s := []int{1, 2, 3, 4, 5, 9, 10, 11}
	<-rxgo.Create([]rxgo.Producer{func(ctx context.Context, next chan<- rxgo.Item) {
		for _, item := range s {
			next <- rxgo.Of(item)
		}
	}}).
		Map(func(c context.Context, i interface{}) (interface{}, error) { // map 1
			tp := i.(int)
			// Simulate a time-consuming operation
			time.Sleep(time.Millisecond * time.Duration(rand.Intn(10)))
			return tp, nil
		}, rxgo.WithPool(10), rxgo.WithBufferedChannel(10)).
		DoOnNext(func(i interface{}) {
			fmt.Printf("%v\n", i) // i want to print 1,2,3,4,5,9,10,11
		})
nlm
nlm

The role of rxgo.Serialize is to guarantee order in the value, thus it needs complete continuity in the indexes. It has no way to guess which indexes it's suppose to drop.

You can solve your problem by separating index from value. Here i used a richer Item type for this.

package main

import (
	"context"
	"fmt"
	"math/rand"
	"time"

	"github.com/reactivex/rxgo/v2"
)

type Item struct {
	Idx   int
	Value int
}

func main() {
	s := []int{1, 2, 3, 4, 5, 9, 10, 11}
	<-rxgo.Create([]rxgo.Producer{func(ctx context.Context, next chan<- rxgo.Item) {
		for i, item := range s {
			next <- rxgo.Of(Item{Idx: i, Value: item})
		}
	}}).
		Map(func(c context.Context, i interface{}) (interface{}, error) { // map 1
			tp := i.(Item)
			// Simulate a time-consuming operation
			time.Sleep(time.Millisecond * time.Duration(rand.Intn(10)))
			return tp, nil
		}, rxgo.WithPool(10), rxgo.WithBufferedChannel(10), rxgo.Serialize(func(i interface{}) int {
			return i.(Item).Idx
		})).
		DoOnNext(func(i interface{}) {
			fmt.Printf("%v\n", i.(Item).Value) // i want to print 1,2,3,4,5,9,10,11
		})
}
started
started time in 6 hours ago
started
started time in 6 hours ago
started
started time in 7 hours ago
started
started time in 7 hours ago
started
started time in 7 hours ago
started
started time in 8 hours ago
Activity icon
fork

yurakhomitsky forked ReactiveX/rxjs

⚡ A reactive programming library for JavaScript
yurakhomitsky Apache License 2.0 Updated
fork time in 9 hours ago
started
started time in 9 hours ago
started
started time in 9 hours ago
started
started time in 12 hours ago
started
started time in 12 hours ago
started
started time in 12 hours ago
started
started time in 13 hours ago
pull request

hoc081098 pull request ReactiveX/rxdart

hoc081098
hoc081098

Update flutter-example.yml

Ignore '**.md'

push

hoc081098 push ReactiveX/rxdart

hoc081098
hoc081098

Update flutter-example.yml (#677)

  • Update flutter-example.yml

  • Update README.md

commit sha: fc0083a8fc9782fe9071c3e27d53af0bdf51b85e

push time in 13 hours ago
Activity icon
delete

hoc081098 in ReactiveX/rxdart delete branch hoc081098-patch-1

deleted time in 13 hours ago
Activity icon
issue

codecov-commenter issue comment ReactiveX/rxdart

codecov-commenter
codecov-commenter

Update flutter-example.yml

Ignore '**.md'

codecov-commenter
codecov-commenter

Codecov Report

Merging #677 (7bab849) into master (4672f1c) will increase coverage by 0.20%. The diff coverage is n/a.

:exclamation: Current head 7bab849 differs from pull request most recent head b3e451e. Consider uploading reports for the commit b3e451e to get more accurate results

@@            Coverage Diff             @@
##           master     #677      +/-   ##
==========================================
+ Coverage   93.52%   93.72%   +0.20%     
==========================================
  Files          74       74              
  Lines        2284     2279       -5     
==========================================
  Hits         2136     2136              
+ Misses        148      143       -5     
Previous