【问题标题】:RxJava - any problems with doing long running task in map and doOnSuccessRxJava - 在 map 和 doOnSuccess 中执行长时间运行任务的任何问题
【发布时间】:2021-03-28 13:54:43
【问题描述】:

考虑以下

class Dummy {
    private fun firstStep(): Single<String> {
        return Single.just("dafe")
                .subscribeOn(Schedulers.io())
    }
    fun action1() {
        firstStep()
                .map {
                    mapStuff(it)
                }
                .doOnError {
                    println("${Thread.currentThread().name} it")
                }
                .doOnSuccess {
                    someVoidAction(it)
                }
                .flatMap { 
                    return@flatMap anotherStep(it)
                }
                .observeOn(Schedulers.trampoline())
                .subscribe( { result ->
                    println(result)
                }, {
                    it.printStackTrace()
                })
    }
    private fun mapStuff(it: String): Int {
        println("mapStuff on thread ${Thread.currentThread().name}")
        Thread.sleep(2000L)
        return it.length
    }
    private fun someVoidAction(i: Int) {
        println("someVoidAction on thread ${Thread.currentThread().name}")
        Thread.sleep(2000L)
    }
}

我能看到的唯一缺点是:

  1. 可读性不强 - 查看动作链,您无法立即判断“mapStuff”和“doVoidAction”实际上是长时间运行的任务,就像您如何判断“anotherStep”一样
  2. 理论上,人们可能希望为不同的任务使用不同的线程。例如,“mapStuff”可能需要Schedulers.computation() 而不是Schedulers.io()。然而,在实践中,Schedulers.io() 在我的项目中使用了 99% 的时间。那么,我们需要关心吗?
  3. 根据需要,在极少数情况下,我可能希望在“mapStuff”或“doVoidAction”上应用 2 秒超时和“错误恢复”逻辑。但话又说回来,它是情境性的,所以在一般情况下,可以像上面那样以非反应性方式执行“mapStuff”或“doVoidAction”,对吧?

还有其他我没有看到的问题吗?

以 RxJava 方式编写所有内容的缺点是它需要更多的工作,这取决于对 RxJava 的流利程度(或痴迷程度)。

这里的简单虚拟代码非常简单,但在现实生活中可能会变得复杂得多:

fun action2() {
        firstStep()
                .flatMap {
                    mapStuffReactive(it)
                }
                .flatMap {
                    return@flatMap doStuffReactive(it)
                }
                .flatMap {
                    return@flatMap anotherStep(it)
                }
                .observeOn(Schedulers.trampoline())
                .subscribe( { result ->
                    println(result)
                }, {
                    it.printStackTrace()
                })
    }

    private fun doStuffReactive(i: Int): Single<Int> {
        return Completable.fromAction {
            println("someVoidAction $i")
        }
                .delay(2L, TimeUnit.SECONDS, Schedulers.io())
                .andThen(Single.just(i))
    }

    private fun mapStuffReactive(it: String): Single<Int> {
        return Single.just(it.length)
                .delay(2L, TimeUnit.SECONDS, Schedulers.io())
    }

【问题讨论】:

  • 这些“长期运行的任务”是您在地图中添加的...它们是否包含副作用(接触 IO、DB 或服务器)或者它们只是计算密集型的?
  • 是的,他们经常这样做

标签: rx-java reactive-programming rx-java2


【解决方案1】:

Rx Design Guidelines 之后,您永远不应该将导致副作用的代码放在map 中。您应该始终明确显示副作用代码。

导致副作用的代码应该只在创建 observable 时出现,在订阅中,或者很少出现在 do 运算符中。这将使阅读代码的任何人都清楚发生了什么,并且还可以更容易地确定链的哪些部分是可测试的,或不可测试的。

do 运算符中的副作用很好,实际上它们是意料之中的,但是请确保您了解这些副作用会发生在每个 Observable 订阅中。 IMO,如果您可以将代码放入订阅中,请改为这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-15
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 1970-01-01
    相关资源
    最近更新 更多