隨著手機的發展, 其效能已經與電腦越來越接近, 也會有一些複雜耗時的並行任務需要處理, 對於非同步與並行, RxAndroid是我們的最佳選擇. 那麼讓我來使用例項介紹一下吧.
在計算排程器Schedulers.computation()
中, 可以並行處理任務, 核數是Rx根據手機CPU定製的, 在我的華為P8手機(8核)中, 使用的是8個執行緒. 但是根據Java執行緒的最佳配置而言, 8核最佳是9個執行緒, 即執行緒數等於核數+1.
本文原始碼的GitHub下載地址
歡迎Follow我的GitHub: https://github.com/SpikeKing
配置
RxAndroid+ButterKnife, 我是ButterKnife的粉絲.
1 2 3 |
compile 'com.jakewharton:butterknife:7.0.1' compile 'io.reactivex:rxjava:1.1.0' compile 'io.reactivex:rxandroid:1.1.0' |
計算執行緒
MAX
是並行執行的任務數. 使用flatMap
逐個分發到計算執行緒computation
中, 執行耗時任務intenseCalculation
.
1 2 3 4 5 6 7 8 9 10 11 |
// 計算執行緒並行, 8核 public void computePara(View view) { mTvComputeValue.setText("計算中"); Observable.range(MIN, MAX) .flatMap(i -> Observable.just(i) .subscribeOn(Schedulers.computation()) // 使用Rx的計算執行緒 .map(this::intenseCalculation) ) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::computeTag); } |
使用intenseCalculation
模擬耗時任務.
1 2 3 4 5 6 7 8 9 10 |
// 模擬耗時計算 private int intenseCalculation(int i) { try { tag("Calculating " + i + " on " + Thread.currentThread().getName()); Thread.sleep(randInt(100, 500)); return i; } catch (InterruptedException e) { throw new RuntimeException(e); } } |
最大執行緒
最大執行緒數 = CPU核數 + 1
由於CPU的核數是8, 因此我們選擇9個執行緒. 建立執行器executor
, 使用執行器建立Rx的排程器Scheduler
, 處理非同步任務.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// 定製執行緒並行, 9核 public void customPara(View view) { int threadCt = Runtime.getRuntime().availableProcessors() + 1; mTvCustomValue.setText(String.valueOf("計算中(" + threadCt + "執行緒)")); ExecutorService executor = Executors.newFixedThreadPool(threadCt); Scheduler scheduler = Schedulers.from(executor); Observable.range(MIN, MAX) .flatMap(i -> Observable.just(i) .subscribeOn(scheduler) .map(this::intenseCalculation) ).observeOn(AndroidSchedulers.mainThread()) .subscribe(this::customTag); } |
高版本計算CPU核數的方式.
1 |
Runtime.getRuntime().availableProcessors() |
低版本, 參考.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
private int getNumCoresOldPhones() { //Private Class to display only CPU devices in the directory listing class CpuFilter implements FileFilter { @Override public boolean accept(File pathname) { //Check if filename is "cpu", followed by a single digit number if (Pattern.matches("cpu[0-9]+", pathname.getName())) { return true; } return false; } } try { //Get directory containing CPU info File dir = new File("/sys/devices/system/cpu/"); //Filter to only list the devices we care about File[] files = dir.listFiles(new CpuFilter()); //Return the number of cores (virtual CPU devices) return files.length; } catch (Exception e) { //Default to return 1 core return 1; } } |
迴圈賽模式
迴圈賽模式(Round-Robin)
是把資料分組, 按執行緒數分組, 每組9個, 一起傳送處理. 這樣做, 可以減少Observable的建立, 節省系統資源, 但是會增加處理時間, 是空間和時間的綜合考慮.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
int threadCt = Runtime.getRuntime().availableProcessors() + 1; mTvGroupedValue.setText(String.valueOf("計算中(" + threadCt + "執行緒)")); ExecutorService executor = Executors.newFixedThreadPool(threadCt); Scheduler scheduler = Schedulers.from(executor); final AtomicInteger batch = new AtomicInteger(0); Observable.range(MIN, MAX) .groupBy(i -> batch.getAndIncrement() % threadCt) .flatMap(g -> g.observeOn(scheduler).map(this::intenseCalculation)) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::groupedTag); |
這是Compute
\ Max
\ Group
三種效果的時間對比, 可以發現Max的時間最優, 因為比Compute多一個執行緒, 但是Group會更加節省資源一些. 根據所執行的並行任務使用Rx吧.
效果
OK, that’s all! Enjoy it!
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!