在rx中实现资源队列

时间:2015-10-28 12:12:20

标签: reactive-programming rx-java

我有一个热的可观察Observable<Resource> resources代表可消耗资源,我想为这些资源排队消费者Action1<Resource>。资源最多可由1个消费者使用。一旦从resources推送新值,就不应该使用它。如果我的消费者也被热的观察所包裹,那么我所追求的大理石图将是

--A--B--C--D--E--
----1----2--34---

----A----C--D-E--
----1----2--3-4--

我使用PublishSubjectzip管理了一个简单的实现,但这仅适用于在发布新资源之前消耗每个资源(即代替所需的序列[A1, C2,D3,E4]这种实现实际上会产生[A1,B2,C3,D4])。

这是我第一次尝试使用rx而且我已经同时使用了delayjoin,但似乎无法得到我所知道的后。我也读过,理想情况下应该避免使用Subjects,但我不知道如何实现这一点。

public class ResourceQueue<Resource> {
    private final PublishSubject<Action1<Resource>> consumers = PublishSubject.create();

    public ResourceQueue(Observable<Resource> resources) {
        resources.zipWith(this.consumers, new Func2<Resource, Action1<Resource>, Object>() {
            @Override
            public Object call(Resource resource, Action1<Resource> consumer) {
                consumer.execute(resource);
                return null;
            }
        }).publish().connect();
    }

    public void queue(final Action1<Resource> consumer) {
        consumers.onNext(consumer);
    }
}

有没有办法实现我之后的目标?是否有更多的&rx-y&#39;解决方案的方法?

1 个答案:

答案 0 :(得分:0)

编辑:使用withLatesFrom更改了combineLatest建议。

我能想到的唯一解决方案是使用combineLatest获取所有可能的组合,手动排除您不需要的组合:

    final ExecutorService executorService = Executors.newCachedThreadPool();

    final Observable<String> resources = Observable.create(s -> {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                final List<Integer> sleepTimes = Arrays.asList(200, 200, 200, 200, 200);
                for (int i = 0; i < sleepTimes.size(); i++) {
                    try {
                        Thread.sleep(sleepTimes.get(i));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    String valueOf = String.valueOf((char) (i + 97));
                    System.out.println("new resource " + valueOf);
                    s.onNext(valueOf);
                }
                s.onCompleted();
            }
        };
        executorService.submit(r);
    });
    final Observable<Integer> consumers = Observable.create(s -> {

        Runnable r = new Runnable() {
            @Override
            public void run() {
                final List<Integer> sleepTimes = Arrays.asList(300, 400, 200, 0);
                for (int i = 0; i < sleepTimes.size(); i++) {
                    try {
                        Thread.sleep(sleepTimes.get(i));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println("new consumer " + (i + 1));
                    s.onNext(i + 1);
                }
                s.onCompleted();
            };
        };
        executorService.submit(r);

    });

    final LatestValues latestValues = new LatestValues();
    final Observable<String> combineLatest = Observable.combineLatest(consumers, resources, (c, r) -> {
        if (latestValues.alreadyProcessedAnyOf(c, r)) {
            return "";
        }
        System.out.println("consumer " + c + " will consume resource " + r);
        latestValues.updateWithValues(c, r);

        return c + "_" + r;
    });

    combineLatest.subscribe();

    executorService.shutdown();
    executorService.awaitTermination(10, TimeUnit.SECONDS);

持有最新消费者和资源的班级。

static class LatestValues {
    Integer latestConsumer = Integer.MAX_VALUE;
    String latestResource = "";

    public boolean alreadyProcessedAnyOf(Integer c, String r) {
        return latestConsumer.equals(c) || latestResource.equals(r);
    }

    public void updateWithValues(Integer c, String r) {
        latestConsumer = c;
        latestResource = r;
    }
}