在 'high traffic' 代码中使用 RxJava 时的对象分配?
Object allocation when using RxJava in 'high traffic' code?
我最近才开始探索 RxJava,并将其应用于我项目的一小部分。事实证明这部分很小但是有 'high traffic':它被其他组件调用了很多。一个例子是网络客户端被反复调用以获取远程数据,对响应应用一些转换,然后触发回调事件。假设这些转换是轻量级的,所以我可以在主线程上完成:
restService.getData() // retrofit interface that returns Observable<T>
.observeOn(AndroidSchedulers.mainThread())
.map(data -> someMapping(data))
.map(data -> someOtherMapping(data))
.subscribe(this::fireResponseCallback, this::fireErrorCallback)
现在不用 RxJava 也能做到同样的事情:
restService.getData() // retrofit interface that returns Call<T>
.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
T data = response.body();
data = someMapping(data);
data = someOtherMapping(data);
fireResponseCallback(data);
}
@Override
public void onFailure(Call<T> call, Throwable t) {
fireErrorCallback(t);
}
});
我对 RxJava 的观察是它在内存中创建了更多的对象。对于上面的示例,每次执行都会经过 4 个 lambda 表达式,每个都会生成 1 个匿名实例化 class(Func1<>
或 Action1<>
)。如果没有 RxJava,你只有 1 个匿名实例化 class (Callback<T>
)。随着同一逻辑被多次触发,这种差异会迅速扩大。我想知道这是否是我在使用 RxJava 时应该注意的事情?如果是,那么减少对象数量的最佳做法是什么?
是的,RxJava 1.x 为响应式序列分配了比理论上需要更多的对象(由于某些设计选择),但它不应该那么激烈。它的分配率对于同步本地序列很明显,但对于基于网络的序列很少。
如果您的 Action 和 Func lambda 是纯的,您可以在成员字段中预先分配它们,并在 lambda 中重用它们的引用。另外,如果restService.getData()
是多次消耗的,你可以将整个链条保存到一个字段中,需要的时候调用subscribe
即可。
class DataAccess {
final RestService restService;
final Observable<T> call = restService.getData()
.observeOn(AndroidSchedulers.mainThread())
.map(data -> someMapping(data))
.map(data -> someOtherMapping(data));
final Action1<T> consumer = this::fireResponseCallback;
final Action1<Throwable> errorHandler = this::fireErrorCallback;
DataAccess(RestService restService) {
this.restService = restService;
}
void doDataAccess() {
call.subscribe(consumer, errorHandler);
}
}
我最近才开始探索 RxJava,并将其应用于我项目的一小部分。事实证明这部分很小但是有 'high traffic':它被其他组件调用了很多。一个例子是网络客户端被反复调用以获取远程数据,对响应应用一些转换,然后触发回调事件。假设这些转换是轻量级的,所以我可以在主线程上完成:
restService.getData() // retrofit interface that returns Observable<T>
.observeOn(AndroidSchedulers.mainThread())
.map(data -> someMapping(data))
.map(data -> someOtherMapping(data))
.subscribe(this::fireResponseCallback, this::fireErrorCallback)
现在不用 RxJava 也能做到同样的事情:
restService.getData() // retrofit interface that returns Call<T>
.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
T data = response.body();
data = someMapping(data);
data = someOtherMapping(data);
fireResponseCallback(data);
}
@Override
public void onFailure(Call<T> call, Throwable t) {
fireErrorCallback(t);
}
});
我对 RxJava 的观察是它在内存中创建了更多的对象。对于上面的示例,每次执行都会经过 4 个 lambda 表达式,每个都会生成 1 个匿名实例化 class(Func1<>
或 Action1<>
)。如果没有 RxJava,你只有 1 个匿名实例化 class (Callback<T>
)。随着同一逻辑被多次触发,这种差异会迅速扩大。我想知道这是否是我在使用 RxJava 时应该注意的事情?如果是,那么减少对象数量的最佳做法是什么?
是的,RxJava 1.x 为响应式序列分配了比理论上需要更多的对象(由于某些设计选择),但它不应该那么激烈。它的分配率对于同步本地序列很明显,但对于基于网络的序列很少。
如果您的 Action 和 Func lambda 是纯的,您可以在成员字段中预先分配它们,并在 lambda 中重用它们的引用。另外,如果restService.getData()
是多次消耗的,你可以将整个链条保存到一个字段中,需要的时候调用subscribe
即可。
class DataAccess {
final RestService restService;
final Observable<T> call = restService.getData()
.observeOn(AndroidSchedulers.mainThread())
.map(data -> someMapping(data))
.map(data -> someOtherMapping(data));
final Action1<T> consumer = this::fireResponseCallback;
final Action1<Throwable> errorHandler = this::fireErrorCallback;
DataAccess(RestService restService) {
this.restService = restService;
}
void doDataAccess() {
call.subscribe(consumer, errorHandler);
}
}