Reactivecocoa: كيفية توفير الضغط العكسي (منتج إشارة كسول يجلب المزيد من البيانات أثناء استهلاك البيانات)

تم إنشاؤها على ٢٠ أبريل ٢٠١٦  ·  6تعليقات  ·  مصدر: ReactiveCocoa/ReactiveCocoa

أحاول معرفة كيفية إنشاء SignalProducer الذي سيجلب بشكل متكرر الجزء التالي من البيانات عندما يتم استهلاك الدفق بالكامل.
لدي تطبيق ، لكن آلية الضغط المرتد لا تعمل إذا تم استدعاء المنتج observeOn على المنتج. ما يبدو أنه يحدث هو أن المنتج يستمر في جلب البيانات الجديدة على الرغم من أن العميل لم يستهلك الدفق بالكامل.

أي فكرة كيف يمكنني تحقيق ما أريد؟ هل هذا ممكن فعلا؟

شكرا!

public func streamMessages(from startOffset: Offset = Offset(value: 0), toExclusive endOffsetOpt : Offset? = .None,
                               includeTransient: Bool = true) -> SignalProducer<Message, NoError> {

        func streamMessagesChunk(from: Offset) -> SignalProducer<Message, NoError> {
            func waitForNewMessageAvailable(from: Offset) -> SignalProducer<Offset?, NoError> {
                return self.lastOffsetIncludingTransient(includeTransient).producer
                    .filter{ offsetOpt in offsetOpt.map {offset in offset >= from } ?? false }
                    .take(1)
            }

            let streamMessagesProducer = self.fetchMessages(10, from: from, includeTransientMessages: includeTransient)
                .flatMap(.Concat){ messages in SignalProducer<Message, NoError>(values: messages)}

            return waitForNewMessageAvailable(from)
                .then(streamMessagesProducer)
        }

        func streamNextBatch(from: Offset, observer: Observer<Message, NoError>, observerDisposable: CompositeDisposable) -> Void {
            func hasReachedEndOffset(currentOffset: Offset) -> Bool {
                return endOffsetOpt.map{ endOffset in endOffset == currentOffset } ?? false
            }

            print("StreamNextBatch \(from)")

            streamMessagesChunk(from).startWithSignal { signal, signalDisposable in
                var lastOffset: Offset = from
                let disposableHandle = observerDisposable.addDisposable(signalDisposable)

                signal.observe { switch $0 {
                    case let .Failed(error): observer.sendFailed(error)
                    case .Interrupted: observer.sendInterrupted()
                    case .Completed:
                        disposableHandle.remove()
                        streamNextBatch(lastOffset.next, observer: observer, observerDisposable: observerDisposable)
                    case .Next(let message):
                        if hasReachedEndOffset(message.offset) {
                            disposableHandle.remove()
                            observer.sendCompleted()
                        } else {
                            lastOffset = message.offset
                            observer.sendNext(message)
                        }
                    }
                }
            }
        }

        return SignalProducer<Message, NoError> { observer, observerDisposable in
            streamNextBatch(startOffset, observer: observer, observerDisposable: observerDisposable)
        }
    }

func testShouldStreamMessagesWaitingForFutureMessages() {
        let expectation = self.expectationWithDescription("Test")
        let messages = (0...50000).map{value in self.createKafkaData(UInt64(value)) }
        let nextMessages = (50001...65000).map{value in self.createKafkaData(UInt64(value)) }

        try! self.sut.publishMessages(messages, persist: false).get()

        let messageCountFuture = self.sut
            .streamMessages(from: Offset(value: 45), toExclusive: Offset(value: 60000), includeTransient: true)
            .observeOn(QueueScheduler())
            .map{ m in print("sleeping at \(m.data)"); sleep(1); return 1 }
            .reduce(0, +)
            .toFuture()

        messageCountFuture.onSuccess{ count in
            expect(count) == 15
            expectation.fulfill()
        }

        try! self.sut.publishMessages(nextMessages, persist: false).get()

        self.waitForExpectationsWithTimeout(30, handler: nil)
    }

     func createKafkaData(number: UInt64) -> String {
        return "message \(number)"
    }
question

ال 6 كومينتر

_اسف على التأخير الطويل في الرد. لقد عملنا على حل الكثير من المشكلات القديمة حيث انسحب بعض المساهمين.

للأسف ، AFAIK لا توجد حاليًا طريقة لتوفير الضغط الخلفي عبر المجدولين. 😞

هل تعرف ما إذا كانت هناك أطر تفاعلية أخرى توفر طريقة للقيام بذلك؟ أعتقد بالتأكيد أنه مفهوم مثير للاهتمام.

على حد علمي ، لا تدعم الأطر من عائلة Rx الضغط المرتد بشكل عام ، ولكن هناك تنفيذ واحد معين للتدفقات (akka-streams) يدعمها: http://www.smartjava.org/content/visualizing-back-pressure -و-رد الفعل-تيارات-عكا-تيارات-احصائياتd-grafana-and-influxdb

الفكرة هي أن البيانات تتدفق في اتجاه مجرى النهر ويتدفق الطلب إلى أعلى ، وبالتالي فإن المستلم يتحكم دائمًا في الحد الأقصى لمعدل البيانات الواردة.

أيضًا ، لا يبدو أن RxSwift بها ضغط عكسي ، ولكن يبدو أن عامل التشغيل المؤجل سيكون كافياً لتلبية الاحتياجات نفسها: http://reactivex.io/documentation/operators/defer.html

ما مدى صعوبة وجود عامل مؤجل في ReactiveCocoa؟

ليس من الصعب. لقد فعلت شيئًا مشابهًا في ريكس . على الرغم من أنه يبدو وكأنه يطلب نسخة معممة. بدلاً من الفاصل الزمني للتأخير ، قد ترغب في إشارة المشغل / معلمة المنتج لتأجيل الاشتراك.

neilpa ، سنحتاج إلى تأجيل الاشتراك حتى ينتهي المستهلك من استهلاك البث. يعمل هذا بشكل جيد مع ReactiveCocoa (المثال أعلاه) حتى تبدأ الاشتراك في برنامج جدولة مختلف.

سأغلق هذا منذ أن تمت الإجابة على سؤالك. إذا كنت ترغب في تقديم اقتراح لشيء ما ، فلا تتردد في فتح عدد جديد أو العلاقات العامة!

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات