bco*_*rso 245 java multithreading thread-safety rx-java rx-android
在RxJava中有5种不同的调度程序可供选择:
immediate():创建并返回一个在当前线程上立即执行工作的Scheduler.
trampoline():创建并返回一个调度程序,该调度程序对当前工作完成后要执行的当前线程进行排队.
newThread():创建并返回一个Scheduler,为每个工作单元创建一个新的Thread.
computation():创建并返回用于计算工作的Scheduler.这可以用于事件循环,处理回调和其他计算工作.不要在此调度程序上执行IO绑定的工作.使用调度程序.io()代替.
io():创建并返回一个用于IO绑定工作的Scheduler.该实现由Executor线程池支持,该线程池将根据需要增长.这可用于异步执行阻塞IO.不要在此调度程序上执行计算工作.使用调度程序.计算()而不是.
前3个调度程序非常自我解释; 但是,我对计算和io有点困惑.
java.io)和files(java.nio.files)吗?它用于数据库查询吗?它是用于下载文件还是访问REST API?Dav*_*ten 322
很棒的问题,我认为文档可以提供更多细节.
io()由无限制的线程池支持,这是你用于非计算密集型任务的东西,这些东西不会对CPU造成太大负担.因此,与文件系统的交互,与不同主机上的数据库或服务的交互就是很好的例子.computation()由有限的线程池支持,其大小等于可用处理器的数量.如果你试图在可用处理器之外并行安排cpu密集型工作(比如使用newThread()),那么当线程争夺处理器时,你就会面临线程创建开销和上下文切换开销,并且它可能会受到很大的性能影响.computation()CPU密集型工作,否则你将无法获得良好的CPU利用率.io()由于2中讨论的原因要求进行计算工作是不好的io(),如果你io()并行安排了一千个计算任务,那么这千个任务中的每一个都将拥有自己的线程并争夺CPU产生的上下文切换成本.最重要的一点是Schedulers.io和Schedulers.computation都由无界线程池支持,而不是问题中提到的其他线程池。仅当Executor使用newCachedThreadPool(不受自动回收线程池限制)创建时, Schedulers.from(Executor)才共享此特征。
正如之前的回复和网络上的多篇文章中充分解释的那样,应谨慎使用Schedulers.io和Schedulers.computation,因为它们针对其名称中的工作类型进行了优化。但是,在我看来,它们最重要的作用是为反应流提供真正的并发性。
与新手的看法相反,反应式流本质上不是并发的,而是本质上异步和顺序的。正是出于这个原因,只有当 I/O 操作阻塞时才应使用Schedulers.io(例如:使用诸如 Apache IOUtils FileUtils.readFileAsString(...)之类的阻塞命令),从而会冻结调用线程,直到操作被阻塞为止。完毕。
使用异步方法(例如 Java AsynchronousFileChannel(...))不会在操作期间阻塞调用线程,因此没有必要使用单独的线程。事实上,Schedulers.io线程并不真正适合异步操作,因为它们不运行事件循环,并且回调永远不会被调用。
相同的逻辑适用于数据库访问或远程 API 调用。如果您可以使用异步或反应式 API 进行调用,请不要使用Schedulers.io 。
回到并发。您可能无法访问异步或反应式 API 来异步或并发执行 I/O 操作,因此唯一的选择是在单独的线程上分派多个调用。唉,反应式流在其末端是顺序的,但好消息是flatMap ()运算符可以在其核心引入并发性。
并发性必须在流构造中构建,通常使用flatMap()运算符。这个强大的运算符可以配置为在内部为flatMap()嵌入的 Function<T, R> 提供多线程上下文。该上下文由多线程调度程序(例如Scheduler.io或Scheduler.computation )提供。
在有关 RxJava2调度程序和并发的文章中查找更多详细信息,您可以在其中找到有关如何顺序和并发使用调度程序的代码示例和详细说明。
希望这可以帮助,
软杰克