自开始以来,我一直在学习Rxswift并将其应用于项目。我希望您的帮助使您对一个概念更加放心。
我知道用户界面中的更改应在Mainscheduler上执行,并且如果不使用.observeOn(MainSchedule…
,则应明确使用Drivers
。
我的疑问是:通常,我在执行网络请求时应该明确切换到后台线程吗?。
我还没有找到很多关于这一点的文献,但是我已经阅读了一些项目代码,但大多数都没有,但是有一些是。那些最终使用Drivers
或.observeOn(MainSchedule…
在UI上进行更改。
例如,在https://www.thedroidsonroids.com/blog/rxswift-examples-4-multithreading中,他说
So as you may guessed, in fact everything we did was done on a MainScheduler. Why? Because our chain starts from searchBar.rx_text and this one is guaranteed to be on MainScheduler. And because everything else is by default on current scheduler – well our UI thread may get overwhelmed. How to prevent that? Switch to the background thread before the request and before the mapping, so we will just update UI on the main thread
所以他解决他提到的问题的方法是明确声明
.observeOn(ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .Background))
假设API请求无论如何都会在后台执行,这是在后台执行所有其他计算,对吗?
这是一个好习惯吗? 我是否应该在每个API请求中将其显式更改为后台,然后仅在必要时才更改回Main?
如果是这样,什么是最好的方法?要在背景上观察,然后在Main上观察?或在后台订阅并在Main上进行观察,如本要点所述: https://gist.github.com/darrensapalo/711d33b3e7f59b712ea3b6d5406952a4 ?
或者也许是另一种方式?
P.S .:对旧代码感到抱歉,但是在我发现的链接中,这些链接更适合我的问题。
答案 0 :(得分:1)
你是对的。当然,实际的网络请求以及等待和组合响应都是在后台线程上完成的。之后,会发生什么情况取决于您使用的网络层。
例如,如果您使用的是URLSession,则响应已经在后台线程中返回,因此不需要调用observeOn
来执行除返回主线程之外的任何其他操作,并且会降低性能。换句话说,在回答您的问题时,您无需在每个请求上都切换到后台线程,因为它已为您完成。
我在文章中看到作者是在Alamofire的上下文中谈话的,而Alamofire在主线程上有明确的响应。因此,如果您使用Alamofire或其他在主线程上进行响应的网络层,则如果响应的处理成本很高,则应考虑切换到后台线程。如果您要做的只是从结果字典中创建一个对象并将其推向视图,则在上下文中进行切换可能会过大,并且考虑到您已经不得不通过一次上下文切换而遭受痛苦,因此实际上可能会降低性能。
我觉得同样重要的是,对于任何一个网络层,调用subscribeOn
都是毫无意义的。这只会更改发出请求的线程,而不是等待响应的后台线程,也不会更改返回响应的线程。网络层将决定用于将数据推出的线程,subscribeOn
无法更改。最好的办法是使用observeOn
将响应之后的数据流重新路由到另一个线程。 subscribeOn
运算符用于同步操作,而不是网络请求。
答案 1 :(得分:-1)
通常,即,如果您未指定任何调度程序,则Rx是同步。
其余的内容实际上取决于您的用例。在四个实例中,所有UI操作都必须在主线程调度程序上进行。
后台工作,包括网络请求,应在后台调度程序上运行。哪个-取决于并发/串行执行的优先级和偏好。
.subscribeOn()
定义了工作的完成位置,.observeOn()
定义了处理结果的位置。
因此,您可以回答特定问题:如果网络呼叫的结果将反映在用户界面中,则必须在后台调度程序上订阅,而在主调度上观察。
您可以这样声明调度程序(仅作为示例):
static let main = MainScheduler.instance
static let concurrentMain = ConcurrentMainScheduler.instance
static let serialBackground = SerialDispatchQueueScheduler.init(qos: .background)
static let concurrentBackground = ConcurrentDispatchQueueScheduler.init(qos: .background)
static let serialUtility = SerialDispatchQueueScheduler.init(qos: .utility)
static let concurrentUtility = ConcurrentDispatchQueueScheduler.init(qos: .utility)
static let serialUser = SerialDispatchQueueScheduler.init(qos: .userInitiated)
static let concurrentUser = ConcurrentDispatchQueueScheduler.init(qos: .userInitiated)
static let serialInteractive = SerialDispatchQueueScheduler.init(qos: .userInteractive)
static let concurrentInteractive = ConcurrentDispatchQueueScheduler.init(qos: .userInteractive)
P.S。一些第三方库可能提供可观察的对象,这些可观察的对象已预先配置为在后台调度程序上执行。在这种情况下,无需显式调用.subscribeOn()
。但是您需要确定是否是这种情况。
再回顾一下
通常情况下,执行网络请求时是否应该显式切换到后台线程?-是的,除非有图书馆为您提供
我应该在每个API请求中将其显式更改为后台,然后仅在必要时才更改回Main吗?-是
如果是这样,什么是最好的方法? [...] 在后台订阅并在Main上进行观察