src:
http://ken.pepple.info/openstack/2011/04/22/openstack-nova-architecture/
http://ken.pepple.info/openstack/2012/09/25/openstack-folsom-architecture/
notes:
14'5/29 :
- a more straight forward explain for OpenStack
https://drive.google.com/file/d/0B543p5wfySTQYU1HZWFXcnNhNHM/edit?usp=sharing
(The Implementation of OpenStack Cinder and Integration with NetApp and Ceph.pdf)
https://drive.google.com/file/d/0B543p5wfySTQZTZlWnY1Q00wTkk/edit?usp=sharing
14'5/30:
- Cinder could combine w/ SAN (here is NetApp) or CEPH pool
- Cinder support mutibacked , but they can't be combined to one pool
- Ceph could be used for both Cinder and Glance(image source space)
- Perofrnace is mentioned, evaluated w/ 4 tools (TODO)
--------
2014年5月28日 星期三
An Introduction to OpenStack and its use of KVM
src:
http://www.linux-kvm.org/wiki/images/7/7b/Kvm-forum-2013-openstack.pdf
http://www.cs.nchu.edu.tw/~snmlab/CloudMgnt201309/Lab3.html
http://en.community.dell.com/techcenter/b/techcenter/archive/2011/06/01/virtualizing-approaches-for-openstack-nova-looking-at-the-many-ways-to-skin-the-cactus-kvm-v-xenserver-v-esx.aspx
http://www.doublecloud.org/2013/07/uncover-kvm-and-virtual-machines-in-openstack/
notes:
14'5/28:
- need to check lab (TODO)
14'5/28:
https://drive.google.com/file/d/0B543p5wfySTQYU1HZWFXcnNhNHM/edit?usp=sharing
https://drive.google.com/file/d/0B543p5wfySTQLUdiWGFvN2VJMVU/edit?usp=sharing
-----------------
http://www.linux-kvm.org/wiki/images/7/7b/Kvm-forum-2013-openstack.pdf
http://www.cs.nchu.edu.tw/~snmlab/CloudMgnt201309/Lab3.html
http://en.community.dell.com/techcenter/b/techcenter/archive/2011/06/01/virtualizing-approaches-for-openstack-nova-looking-at-the-many-ways-to-skin-the-cactus-kvm-v-xenserver-v-esx.aspx
http://www.doublecloud.org/2013/07/uncover-kvm-and-virtual-machines-in-openstack/
notes:
14'5/28:
- need to check lab (TODO)
14'5/28:
https://drive.google.com/file/d/0B543p5wfySTQYU1HZWFXcnNhNHM/edit?usp=sharing
https://drive.google.com/file/d/0B543p5wfySTQLUdiWGFvN2VJMVU/edit?usp=sharing
-----------------
VMWare Disk Transport Method
src:
http://pubs.vmware.com/vsphere-51/index.jsp?topic=%2Fcom.vmware.vddk.pg.doc%2FvddkDataStruct.5.5.html
notes:
14'5/28:
- there are 5 method to access external disk
14'5/28 :
https://drive.google.com/file/d/0B543p5wfySTQTEVuOE1Cc1l0Mms/edit?usp=sharing
---------------------
http://pubs.vmware.com/vsphere-51/index.jsp?topic=%2Fcom.vmware.vddk.pg.doc%2FvddkDataStruct.5.5.html
notes:
14'5/28:
- there are 5 method to access external disk
14'5/28 :
https://drive.google.com/file/d/0B543p5wfySTQTEVuOE1Cc1l0Mms/edit?usp=sharing
---------------------
How to Benchmark Object Storage Solutions: The CPU Bottleneck Case Study
src:
http://cloud.media.seagate.com/2014/02/25/how-to-benchmark-object-storage-solutions-the-cpu-bottleneck-case-study/
notes:
14'5/28:
COSBench for object storage evaluation (TODO)
14'5/28:
https://drive.google.com/file/d/0B543p5wfySTQM2FScFFBZzVPcm8/edit?usp=sharing
--------------
http://cloud.media.seagate.com/2014/02/25/how-to-benchmark-object-storage-solutions-the-cpu-bottleneck-case-study/
notes:
14'5/28:
COSBench for object storage evaluation (TODO)
14'5/28:
https://drive.google.com/file/d/0B543p5wfySTQM2FScFFBZzVPcm8/edit?usp=sharing
--------------
2014年5月27日 星期二
RDMA
src:
http://wiki.mbalib.com/zh-tw/RDMA
notes:
14'5/28 :
RDMA just like what TCE could provide.
RDMA's prons : it needs to install both on source and target system?
14'5/28 :
https://drive.google.com/file/d/0B543p5wfySTQdEctQmgwSVdFdTA/edit?usp=sharing
-----------------
http://wiki.mbalib.com/zh-tw/RDMA
notes:
14'5/28 :
RDMA just like what TCE could provide.
RDMA's prons : it needs to install both on source and target system?
14'5/28 :
https://drive.google.com/file/d/0B543p5wfySTQdEctQmgwSVdFdTA/edit?usp=sharing
-----------------
TOE
src:
http://life.iiietc.ncu.edu.tw/xms/content/show.php?id=9421
notes:
14'5/28 : TOE feature
- relief tedious interrupt. Actually for normal NIC, NUMA could help to reduce it.
- zero copy. No need to copy data from NIC buffer to Application buffer.
-------
http://life.iiietc.ncu.edu.tw/xms/content/show.php?id=9421
notes:
14'5/28 : TOE feature
- relief tedious interrupt. Actually for normal NIC, NUMA could help to reduce it.
- zero copy. No need to copy data from NIC buffer to Application buffer.
-------
| |||
|
2014年5月23日 星期五
红帽专家解读:虚拟化技术KVM和XEN的区别
src:
http://www.cioage.com/art/201007/88938.htm
notes:
14'5/23 :
- KVM is Full Virtualization, XEN is w/ additional Para Virtualization.
- RedHat will focus on KVM instead of XEN in the future
-----------
http://www.cioage.com/art/201007/88938.htm
notes:
14'5/23 :
- KVM is Full Virtualization, XEN is w/ additional Para Virtualization.
- RedHat will focus on KVM instead of XEN in the future
-----------
红帽专家解读:虚拟化技术KVM和XEN的区别
导读:从架构上讲,xen是自定制的hypervisor,对硬件的资源管理和调度,对虚拟机的生命周期管理等,都是从头开始写的。 KVM全称是Kernel-based Virtual Machine, kernel代表的是Linux kernel。KVM是一个特殊的.....
答:XEN目前支持Full Virtualization(全虚拟化) 和 Para Virtualization.
Full Virtualization的好处在于现有的x86架构的操作系统可以不用修改,直接运行在虚拟机上。 Para Virtualization的好处是性能好,但是虚拟机上运行的操作系统内核要修改。
目前主流的厂家的虚拟化重点都是放在Full Virtualization上面。
KVM采用的是Full Virtualization,需要CPU支持VT。 如何确认你的CPU是否支持VT,查看cpu flag, intel cpu flag 会有 "vmx" , amd cpu flag 会有 "svm".
从架构上讲,xen是自定制的hypervisor,对硬件的资源管理和调度,对虚拟机的生命周期管理等,都是从头开始写的。 KVM全称是Kernel-based Virtual Machine, kernel代表的是Linux kernel。KVM是一个特殊的模块,Linux kernel加载此模块后,可以将Linux kernel 变成hypervisor,因为Linux kernel已经可以很好的实现对硬件资源的调度和管理,KVM只是实现了对虚拟机生命周期管理的相关工作。 KVM的初始版本只有4万行代码,相对于xen的几百万行代码显得非常简洁。
更多关于KVM架构的信息,请参考KVM白皮书:
http://www.linuxinsight.com/files/kvm_whitepaper.pdf
http://www.linuxinsight.com/files/kvm_whitepaper.pdf
红帽在2007年发布RHEL5,采用的是xen来提供虚拟化功能。从红帽RHEL5.4开始,xen和kvm同时存在。 RHEL5上的xen,红帽会支持到2014年。 后续红帽的重点会放在KVM上面。
(以上问题由红帽中国解决方案架构师/红帽认证架构师 李华 先生解答)
【责任编辑:凌云通 TEL:(010)68479336】
KVM or Xen? Choosing a Virtualization Platform
src:
http://www.linux.com/news/enterprise/systems-management/327628-kvm-or-xen-choosing-a-virtualization-platform
notes:
14'5/23 : KVM get more support generally in the near future.
---------
http://www.linux.com/news/enterprise/systems-management/327628-kvm-or-xen-choosing-a-virtualization-platform
notes:
14'5/23 : KVM get more support generally in the near future.
---------
When Xen was first released in 2002, the GPL'd hypervisor looked likely to take the crown as the virtualization platform for Linux. Fast forward to 2010, and the new kid in town has displaced Xen as the virtualization of choice for Red Hat and lives in the mainline Linux kernel. Which one to choose? Read on for our look at the state of Xen vs. KVM.
Things in virtualization land move pretty fast. If you don't have time to keep up with the developments in KVM or Xen development, it's a bit confusing to decide which one (if either) you ought to choose. This is a quick look at the state of the market between Xen and KVM.
KVM and Xen
Xen is a hypervisor that supports x86, x86_64, Itanium, and ARM architectures, and can run Linux, Windows, Solaris, and some of the BSDs as guests on their supported CPU architectures. It's supported by a number of companies, primarily by Citrix, but also used by Oracle for Oracle VM, and by others. Xen can do full virtualization on systems that support virtualization extensions, but can also work as a hypervisor on machines that don't have the virtualization extensions.
KVM is a hypervisor that is in the mainline Linux kernel. Your host OS has to be Linux, obviously, but it supportsLinux, Windows, Solaris, and BSD guests. It runs on x86 and x86-64 systems with hardware supporting virtualization extensions. This means that KVM isn't an option on older CPUs made before the virtualization extensions were developed, and it rules out newer CPUs (like Intel's Atom CPUs) that don't include virtualization extensions. For the most part, that isn't a problem for data centers that tend to replace hardware every few years anyway — but it means that KVM isn't an option on some of the niche systems like the SM10000 that are trying to utilize Atom CPUs in the data center.
If you want to run a Xen host, you need to have a supported kernel. Linux doesn't come with Xen host support out of the box, though Linux has been shipping with support to run natively as a guest since the 2.6.23 kernel. What this means is that you don't just use a stock Linux distro to run Xen guests. Instead, you need to choose a Linux distro that ships with Xen support, or build a custom kernel. Or go with one of the commercial solutions based on Xen, like Citrix XenServer. The problem is that those solutions are not entirely open source.
And many do build custom kernels, or look to their vendors to do so. Xen is running on quite a lot of servers, from low-cost Virtual Private Server (VPS) providers like Linode to big boys like Amazon with EC2. A TechTarget articledemonstrates how providers that have invested heavily in Xen are not likely to switch lightly. Even if KVM surpasses Xen technically, they're not likely to rip and replace the existing solutions in order to take advantage of a slight technical advantage.
And KVM doesn't yet have the technical advantage anyway. Because Xen has been around a bit longer, it also has had more time to mature than KVM. You'll find some features in Xen that haven't yet appeared in KVM, though the KVM project has a lengthy TODO list that they're concentrating on. (The list isn't a direct match for parity with Xen, just a good idea what the KVM folks are planning to work on.) KVM does have a slight advantage in the Linux camp of being the anointed mainline hypervisor. If you're getting a recent Linux kernel, you've already got KVM built in. Red Hat Enterprise Linux 5.4 included KVM support and the company is dropping Xen support for KVM in RHEL 6.
This is, in part, an endorsement of how far KVM has come technically. Not only does Red Hat have the benefit of employing much of the talent behind KVM, there's the benefit of introducing friction to companies that have cloned Red Hat Enterprise Linux and invested heavily in Xen. By dropping Xen from the roadmap, they're forcing other companies to drop Xen or pick up maintenance of Xen and diverging from RHEL. This means extra engineering costs, requiring more effort for ISV certifications, etc.
KVM isn't entirely on par with Xen, though it's catching up quickly. It has matured enough that many organizations feel comfortable deploying it in production. So does that mean Xen is on the way out? Not so fast.
There Can Be Only One?
The choice of KVM vs. Xen is as likely to be dictated by your vendors as anything else. If you're going with RHEL over the long haul, bank on KVM. If you're running on Amazon's EC2, you're already using Xen, and so on. The major Linux vendors seem to be standardizing on KVM, but there's plenty of commercial support out there for Xen. Citrix probably isn't going away anytime soon.
It's tempting in the IT industry to look at technology as a zero sum game where one solution wins and another loses. The truth is that Xen and KVM are going to co-exist for years to come. The market is big enough to support multiple solutions, and there's enough backing behind both technologies to ensure that they do well for years to come.
2014年5月5日 星期一
[Android] 多執行緒-Handler和Thread的關係
src:
http://j796160836.pixnet.net/blog/post/29895257-%5Bandroid%5D-%E5%A4%9A%E5%9F%B7%E8%A1%8C%E7%B7%92-handler%E5%92%8Cthread%E7%9A%84%E9%97%9C%E4%BF%82-%EF%BC%882%EF%BC%89
notes:
---------
Thread t1=new Thread(r1);
http://j796160836.pixnet.net/blog/post/29895257-%5Bandroid%5D-%E5%A4%9A%E5%9F%B7%E8%A1%8C%E7%B7%92-handler%E5%92%8Cthread%E7%9A%84%E9%97%9C%E4%BF%82-%EF%BC%882%EF%BC%89
notes:
---------
之前寫過一個多執行緒,發現還是寫太亂了,不夠簡單
我重新敘述一下
多執行緒的部分,有幾個名詞
- Runnable 工作包 (要做的事情)
- Thread 執行緒
- Handler
- Message
--------------------------------------------------------------------------
Runnable
就是像是專案管理裡的工作包,說穿了就是要做的事情啦,像是這樣
private Runnable r1=new Runnable () {
public void run() {
//.............................
//做了很多事
}
};
這裡的 r1 就是一個runnable
--------------------------------------------------------------------------
Thread
在Android的世界裡,Thread分成二種
1. 單次型 (Java原有的)
2. 常駐型 (Android特有的)
--------------------------------------------------------------------------
1. 單次型
意指就是給他一件艱巨的任務
他做完就會關閉了
寫法實在有夠簡單
Thread t1=new Thread(r1);
t1.start();
這裡的 r1 是一個runnable
--------------------------------------------------------------------------
2. 常駐型
就是做完事情他不會自動關閉,而是變成一個idle (閒置) 的狀態
閒置意思就是他沒事幹啦~ 要給他事情做
mThread = new HandlerThread("name");
//讓Worker待命,等待其工作 (開啟Thread)
mThread.start();
這樣子就可以建立且執行Thread了
連Runnable也不想打的話可以合併起來
Thread XXX = new Thread(new Runnable()
{
publicvoid run()
{
// ......工作
}
}).start();
要給他事情做要這樣寫
mThreadHandler.post(r1);
有沒有發現,單次型的Thread就是把事情定義下來然後呼叫start()
開始跑,跑完關閉
而常駐型的話,反而是讓你先start()
然後post(r1) 給他事情做,做完就閒置
請務必記得不用這個Thread的時候要把他關閉
if (mThread != null)
mThread.quit();
mThread.quit();
大部分的情況,常駐型的Thread
在onCreate()裡面建立Thread
在onDestory()裡面關閉Thread
--------------------------------------------------------------------------
Handler
那甚麼是Handler呢?
你可以想成是一個服務的窗口
給他事情做的地方
寫法有二種
1. mUI_Handler.post(r2);
2. mUI_Handler.sendEmptyMessage(MSG_UPLOAD_OK);
2. mUI_Handler.sendEmptyMessage(MSG_UPLOAD_OK);
第一種就是直接給他一個Runnable,讓他去執行
第二種就是傳一個Message給他
Handler的建立
private Handler mUI_Handler = new Handler();
這樣會建立一個基於Main Thread (UI Thread)的Handler
--------------------------------------------------------------------------
Message
這東西不複雜,剛剛不是還在講Runnable嘛?
Message就是要一言以蔽之,用一個值 (一句話)
代表一堆事情(Runnable)
代表一堆事情(Runnable)
先看看Handler的變形吧
Handler的建立
private Handler mUI_Handler = new Handler();
這樣會建立一個基於Main Thread (UI Thread)的Handler
以下是他的變形
private Handler mUI_Handler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case MSG_UPLOAD_OK:
// ..............
break;
}
}
};
這樣會建立一個基於Main Thread (UI Thread)的Handler
有一個窗口,有一個地方可以處理Message的地方 ( 就是handleMessage() )
這裡用一個switch case的格式表示
msg.what 就是你訊息的內容
MSG_UPLOAD_OK 這就是你的訊息了(自己自訂)
像這樣
privatestaticfinalint MSG_UPLOAD_OK= 0x00000001;
說穿了就是個int而已
要使用的時候就這樣
mUI_Handler.sendEmptyMessage(MSG_UPLOAD_OK);
可以使用帶參數的寫法
可以使用帶參數的寫法
mUI_Handler.obtainMessage(MSG_UPLOAD_OK, arg1, arg2).sendToTarget();
或是
mUI_Handler.obtainMessage(MSG_UPLOAD_OK, obj1).sendToTarget();
這樣可以帶二個int去,或是直接帶object給他(收到了之後再去轉型...)
Java Handler & Thread
src:
http://cw1057.blogspot.tw/2011/10/android-handler.html
notes:
---------
http://cw1057.blogspot.tw/2011/10/android-handler.html
notes:
---------
Android Handler 筆記
每個 app 有一個 process,每個 process 可以有多個 thread,大部分的時候都只會有一個 thread 叫做 main thread。
Android app 的四大要角:activity、service、receiver、provider,都是由 main thread 負責執行。
因為 main thread 要做的事情太多,所以就有一個 message queue 叫做 main queue,紀錄了所有 main thread 要做的事情,或者反過來說,要交由 main thread 處理的事情就丟到 main queue 就好了。
由於 main thread 負責 UI 的互動,像是 user 按下一個按鈕這樣一個動作都會丟到 main queue 去,所以為了不讓 user 枯等,message 在 main queue 待超過五秒鐘或者 main thread 處理一個 message 超過五秒鐘,系統就會丟出 ANR(Application Not Resopnding),所以費時的工作就要另起 thread 來處理或者請 main thread 有空再回來處理。
除了 UI 的互動,sendBroadcast(...) 與 startService(...) 都一樣會被丟到 main queue 裡,等待 main thread 的執行,只有呼叫 local content provider 不會進到 main queue 裡,而是由 main thread 直接執行,猜測應該是因為 content provider 必須同步執行的關係,但如果是 remote content provider 則是由 thread pool 中取得 thread 來執行,外部 client 呼叫 service 也是如此。
除了 main thread,還有從 thread pool 裡出生的 worker thread,主要用來處理外部的呼叫,例如 App A 呼叫 App B 的 service 或者 content provider,就是由 worker thread 負責處理。
為了方便辨識哪個 thread 做了什麼事,可以用簡單的工具程式做紀錄。
先看看怎麼使用 Handler,看完之後就有概念 Handler 是什麼了。
但是上面的步驟有一個遺漏,就是 handler 丟 message 到「哪一個」queue?main queue 或者 worker queue?答案是,在哪一個 thread 建立的 handler 就丟到那一個 thread 的 queue。
也就是說,Handler 除了可以是同一個 thread 的溝通工具,也可以是不同 thread 間的溝通工具,只要可以拿到那一個 thread 的 handler。
舉例說明 Main thread, main queue, worker threads, worker queues, and handlers 的關係與互動
前面提過,費時的工作可以另起 thread 來處理或者稍後再處理,這邊先來看看後者的情況,假設要加總十個數字或更多,不想殺雞用牛刀起新的 thread,又擔心 main thread 執行超過五秒,就可以在 main thread 裡透過 handler 丟 message 到 main queue 裡,讓 main thread 有空再來處理,且一次處理一小部份,這次沒處理完再丟一次,遞迴到全部加總完為止。
HandlerActivity
另起 thread 處理
同樣的假設狀況,在 main thread 裡起一個 worker thread 來執行運算,並傳給該 worker thread 由 main thread 產生的 handler,供 worker thread 與 main thread 進行溝通。
HandlerActivity
從 log 還可以看出一個顯著的差異,執行時間,延遲執行用了十秒鐘左右,worker thread 不到一秒鐘就結束了,這是因為前者每計算一次就休息一秒鐘造成的差異。
Handler Lifecycle
關於 main queue 與 worker thread 還有一個很重要的特徵,就是當 app 不在前景執行時,包括畫面完全被覆蓋(onStop)或者部份被覆蓋(onPause),main thread 仍會繼續執行 main queue 裡的代辦事項,worker thread 也一樣,唯有在 onDestroy 之後才會停止,這可以從上面的範例看出來,不管是透過 main queue 或者 workder thread 執行計算,都是從 onCreate 就啟動的,不是在 onStart 或者 onResume,有一個測試的方法就是將計算的筆數加大為100筆,並在 worker thread 的 loop 裡呼叫 Thread.sleep(...) 以延長執行時間,一旦 app 啟動後,可以跳回 Home 或上一頁來離開該 app,這時先在 log 看到 main thread 與 worker thread 都仍在執行,再跳回該 app,可以從頁面的計算過程得到證明,但是如果離開太久,該 app 是有可以被強制關閉(onDestroy)的。
由上可知,不可以在 onStart 或者 onResume 啟動 worker thread,否則每次離開再回來或者甚至螢幕轉個方向,就可能產生一個新的 worker thread,是可以用 instance var 來追蹤 thread 以迴避這樣的問題,不過一般 worker thread 的啟動應該是透過 user 的事件驅動,比較不會有這樣的問題發生,但是如果是有記憶的狀況,例如這次沒做完下次要繼續做或者在 app 一起動便要建立 worker thread 的話,那就得要在 onCreate 裡進行了。
最後,如果要中途停止 worker thread,不建議呼叫 Thread.stop(...) ,因為這樣沒辦法控制停止的方式,建議在 thread 裡加一個 flag,當必須終止時,只要更改 flag,讓 thread 可以優雅的打卡下班。
相關文章
Android app 的四大要角:activity、service、receiver、provider,都是由 main thread 負責執行。
因為 main thread 要做的事情太多,所以就有一個 message queue 叫做 main queue,紀錄了所有 main thread 要做的事情,或者反過來說,要交由 main thread 處理的事情就丟到 main queue 就好了。
由於 main thread 負責 UI 的互動,像是 user 按下一個按鈕這樣一個動作都會丟到 main queue 去,所以為了不讓 user 枯等,message 在 main queue 待超過五秒鐘或者 main thread 處理一個 message 超過五秒鐘,系統就會丟出 ANR(Application Not Resopnding),所以費時的工作就要另起 thread 來處理或者請 main thread 有空再回來處理。
除了 UI 的互動,sendBroadcast(...) 與 startService(...) 都一樣會被丟到 main queue 裡,等待 main thread 的執行,只有呼叫 local content provider 不會進到 main queue 裡,而是由 main thread 直接執行,猜測應該是因為 content provider 必須同步執行的關係,但如果是 remote content provider 則是由 thread pool 中取得 thread 來執行,外部 client 呼叫 service 也是如此。
除了 main thread,還有從 thread pool 裡出生的 worker thread,主要用來處理外部的呼叫,例如 App A 呼叫 App B 的 service 或者 content provider,就是由 worker thread 負責處理。
為了方便辨識哪個 thread 做了什麼事,可以用簡單的工具程式做紀錄。
public class Utils { private static final String TAG = "Utils"; public static final void logThread() { Thread t = Thread.currentThread(); Log.d(TAG, "<" + t.getName() + ">id: " + t.getId() + ", Priority: " + t.getPriority() + ", Group: " + t.getThreadGroup().getName()); } }在需要的地方加上 Utils.logThread(),就可以得到類似以下的結果:
10-27 09:38:33.797: DEBUG/Utils(517): <main>id: 1, Priority: 5, Group: main 10-27 09:38:38.848: DEBUG/Utils(517): <Thread-10>id: 10, Priority: 5, Group: mainHandler 是什麼?
先看看怎麼使用 Handler,看完之後就有概念 Handler 是什麼了。
- 先 new 一個 handler
- 使用 handler 丟 message 到 queue 裡
- thread 去 queue 取出 message
- 從 message 可以得到 handler
- thread 去執行 handler 裡叫做 handleMessage 的 callback method
但是上面的步驟有一個遺漏,就是 handler 丟 message 到「哪一個」queue?main queue 或者 worker queue?答案是,在哪一個 thread 建立的 handler 就丟到那一個 thread 的 queue。
也就是說,Handler 除了可以是同一個 thread 的溝通工具,也可以是不同 thread 間的溝通工具,只要可以拿到那一個 thread 的 handler。
舉例說明 Main thread, main queue, worker threads, worker queues, and handlers 的關係與互動
一位主人(user)會有一個管家(main thread)和多位女僕(worker threads),管家得隨侍在主人身邊,不能離開太久(五秒鐘),不然主人會失控(ANR),所以當主人交待事情給管家時,管家可以將事情交待給女僕們。
但是因為事情真的太多了,所以管家和女僕們每個人都會有一本紀錄待辦事項的記事本(main queue and worker queue),管家和女僕們當然希望工作愈少愈好,所以每個人都會把自己的筆記本上鎖,所以要打開筆試本加待辦事項就得有密碼(handler),每個人的密碼都不一樣,要向筆記本的主人要才能拿到密碼。延遲處理
前面提過,費時的工作可以另起 thread 來處理或者稍後再處理,這邊先來看看後者的情況,假設要加總十個數字或更多,不想殺雞用牛刀起新的 thread,又擔心 main thread 執行超過五秒,就可以在 main thread 裡透過 handler 丟 message 到 main queue 裡,讓 main thread 有空再來處理,且一次處理一小部份,這次沒處理完再丟一次,遞迴到全部加總完為止。
HandlerActivity
public class HandlerActivity extends Activity {
private static final String TAG = "HandlerActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Utils.logThread();
// 建立供加總使用的數列
List<Integer> intList = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
intList.add((int) (Math.random() * 10));
}
this.deferWork(intList);
}
private void deferWork(List<Integer> intList) {
// 將數列傳給 handler,一併傳入 acitivity 用來事後更新畫面
CalculatorHandler h = new CalculatorHandler(intList, this);
// 立即丟 message 到 main queue 裡
h.sendEmptyMessage(0);
}
// 供 handler 計算完成後更新畫面
public void show(String msg) {
TextView tv = (TextView) this.findViewById(R.id.tv);
tv.setText(tv.getText() + "\n" + msg);
}
}
CalculatorHandlerpublic class CalculatorHandler extends Handler {
private static final String TAG = "DelayHandler";
private List<Integer> intList;
private HandlerActivity activity;
// 紀錄計算到第幾筆
private int handled = 0;
// 加總結果
private int sum = 0;
public CalculatorHandler(List<Integer> intList, HandlerActivity activity) {
super();
this.intList = intList;
this.activity = activity;
}
@Override
public void handleMessage(Message msg) {
// 如果計算完成,就不再往下執行
if (this.handled >= this.intList.size()) {
// 在這裡可以將計算結果透過 activity 顯示在畫面上
String m = "結果 : " + this.sum;
Log.d(TAG, m);
this.activity.show(m);
return;
}
Utils.logThread();
Integer cur = this.intList.get(this.handled);
this.sum += cur;
String m = "加上第 " + (this.handled + 1) + " 筆數字 " + cur + " 等於 "
+ this.sum;
this.activity.show(m);
Log.d(TAG, m);
// 延遲一秒鐘送出下一個 message 到 main queue,形成 loop 效果
this.sendMessageDelayed(this.obtainMessage(), 1000);
this.handled++;
}
}
可以從 log 看出來都是在 main thread 裡執行的:10-28 13:59:41.663: DEBUG/Utils(2069): <main>id: 1, Priority: 5, Group: main 10-28 13:59:41.693: DEBUG/Utils(2069): <main>id: 1, Priority: 5, Group: main 10-28 13:59:41.693: DEBUG/DelayHandler(2069): 加上第 1 筆數字 0 等於 0 10-28 13:59:42.703: DEBUG/Utils(2069): <main>id: 1, Priority: 5, Group: main 10-28 13:59:42.703: DEBUG/DelayHandler(2069): 加上第 2 筆數字 4 等於 4 10-28 13:59:43.773: DEBUG/Utils(2069): <main>id: 1, Priority: 5, Group: main 10-28 13:59:43.773: DEBUG/DelayHandler(2069): 加上第 3 筆數字 9 等於 13 10-28 13:59:44.828: DEBUG/Utils(2069): <main>id: 1, Priority: 5, Group: main 10-28 13:59:44.833: DEBUG/DelayHandler(2069): 加上第 4 筆數字 3 等於 16 10-28 13:59:45.880: DEBUG/Utils(2069): <main>id: 1, Priority: 5, Group: main 10-28 13:59:45.903: DEBUG/DelayHandler(2069): 加上第 5 筆數字 5 等於 21 10-28 13:59:46.928: DEBUG/Utils(2069): <main>id: 1, Priority: 5, Group: main 10-28 13:59:46.943: DEBUG/DelayHandler(2069): 加上第 6 筆數字 2 等於 23 10-28 13:59:48.005: DEBUG/Utils(2069): <main>id: 1, Priority: 5, Group: main 10-28 13:59:48.023: DEBUG/DelayHandler(2069): 加上第 7 筆數字 0 等於 23 10-28 13:59:49.051: DEBUG/Utils(2069): <main>id: 1, Priority: 5, Group: main 10-28 13:59:49.073: DEBUG/DelayHandler(2069): 加上第 8 筆數字 6 等於 29 10-28 13:59:50.096: DEBUG/Utils(2069): <main>id: 1, Priority: 5, Group: main 10-28 13:59:50.124: DEBUG/DelayHandler(2069): 加上第 9 筆數字 1 等於 30 10-28 13:59:51.146: DEBUG/Utils(2069): <main>id: 1, Priority: 5, Group: main 10-28 13:59:51.174: DEBUG/DelayHandler(2069): 加上第 10 筆數字 1 等於 31 10-28 13:59:52.184: DEBUG/DelayHandler(2069): 結果 : 31
另起 thread 處理
同樣的假設狀況,在 main thread 裡起一個 worker thread 來執行運算,並傳給該 worker thread 由 main thread 產生的 handler,供 worker thread 與 main thread 進行溝通。
HandlerActivity
public class HandlerActivity extends Activity {
private static final String TAG = "HandlerActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Utils.logThread();
// 建立供加總使用的數列
List<Integer> intList = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
intList.add((int) (Math.random() * 10));
}
this.callWorker(intList);
}
private void callWorker(List<Integer> intList) {
// 建立 handler 交由 worker thread 與 main thread 溝通
WorkerHandler handler = new WorkerHandler(this);
// 起一個 worker thread
new Thread(new WorkerThread(intList, handler)).start();
}
// 供 handler 計算完成後更新畫面
public void show(String msg) {
TextView tv = (TextView) this.findViewById(R.id.tv);
tv.setText(tv.getText() + "\n" + msg);
}
}
WorkerHandlerpublic class WorkerHandler extends Handler { private static final String TAG = "WorkerHandler"; public static final String MSG = "msg"; private HandlerActivity activity; public WorkerHandler(HandlerActivity activity) { super(); this.activity = activity; } @Override public void handleMessage(Message msg) { Utils.logThread(); // 取出並輸出從 worker thread 傳進來的訊息 String m = msg.getData().getString(WorkerHandler.MSG); Log.d(TAG, m); this.activity.show(m); } }WorkerThread
public class WorkerThread implements Runnable {
private static final String TAG = "WorkerThread";
private List<Integer> intList;
private WorkerHandler handler;
public WorkerThread(List<Integer> intList, WorkerHandler handler) {
super();
this.intList = intList;
this.handler = handler;
}
@Override
public void run() {
Utils.logThread();
// 直接進行計算,且一口氣完成
int sum = 0;
int cur;
for (int i = 0; i < this.intList.size(); i++) {
cur = this.intList.get(i);
sum += cur;
// 將過程透過 handler 傳給 main thread
this.sendMessage("加上第 " + (i + 1) + " 筆數字 " + cur + " 等於 " + sum);
}
this.sendMessage("結果 : " + sum);
}
private void sendMessage(String m) {
Message msg = this.handler.obtainMessage();
msg.getData().putString(WorkerHandler.MSG, m);
this.handler.sendMessage(msg);
}
}
再從 log 看出差異:10-28 13:57:39.724: DEBUG/Utils(1987): <main>id: 1, Priority: 5, Group: main 10-28 13:57:39.753: DEBUG/Utils(1987): <Thread-10>id: 10, Priority: 5, Group: main 10-28 13:57:39.844: DEBUG/Utils(1987): <main>id: 1, Priority: 5, Group: main 10-28 13:57:39.844: DEBUG/WorkerHandler(1987): 加上第 1 筆數字 5 等於 5 10-28 13:57:39.904: DEBUG/Utils(1987): <main>id: 1, Priority: 5, Group: main 10-28 13:57:39.904: DEBUG/WorkerHandler(1987): 加上第 2 筆數字 0 等於 5 10-28 13:57:39.904: DEBUG/Utils(1987): <main>id: 1, Priority: 5, Group: main 10-28 13:57:39.914: DEBUG/WorkerHandler(1987): 加上第 3 筆數字 4 等於 9 10-28 13:57:39.923: DEBUG/Utils(1987): <main>id: 1, Priority: 5, Group: main 10-28 13:57:39.923: DEBUG/WorkerHandler(1987): 加上第 4 筆數字 7 等於 16 10-28 13:57:39.934: DEBUG/Utils(1987): <main>id: 1, Priority: 5, Group: main 10-28 13:57:39.934: DEBUG/WorkerHandler(1987): 加上第 5 筆數字 4 等於 20 10-28 13:57:39.943: DEBUG/Utils(1987): <main>id: 1, Priority: 5, Group: main 10-28 13:57:39.943: DEBUG/WorkerHandler(1987): 加上第 6 筆數字 0 等於 20 10-28 13:57:39.963: DEBUG/Utils(1987): <main>id: 1, Priority: 5, Group: main 10-28 13:57:39.963: DEBUG/WorkerHandler(1987): 加上第 7 筆數字 6 等於 26 10-28 13:57:39.974: DEBUG/Utils(1987): <main>id: 1, Priority: 5, Group: main 10-28 13:57:39.974: DEBUG/WorkerHandler(1987): 加上第 8 筆數字 0 等於 26 10-28 13:57:39.984: DEBUG/Utils(1987): <main>id: 1, Priority: 5, Group: main 10-28 13:57:39.984: DEBUG/WorkerHandler(1987): 加上第 9 筆數字 4 等於 30 10-28 13:57:39.993: DEBUG/Utils(1987): <main>id: 1, Priority: 5, Group: main 10-28 13:57:40.004: DEBUG/WorkerHandler(1987): 加上第 10 筆數字 4 等於 34 10-28 13:57:40.014: DEBUG/Utils(1987): <main>id: 1, Priority: 5, Group: main 10-28 13:57:40.014: DEBUG/WorkerHandler(1987): 結果 : 34
從 log 還可以看出一個顯著的差異,執行時間,延遲執行用了十秒鐘左右,worker thread 不到一秒鐘就結束了,這是因為前者每計算一次就休息一秒鐘造成的差異。
Handler Lifecycle
關於 main queue 與 worker thread 還有一個很重要的特徵,就是當 app 不在前景執行時,包括畫面完全被覆蓋(onStop)或者部份被覆蓋(onPause),main thread 仍會繼續執行 main queue 裡的代辦事項,worker thread 也一樣,唯有在 onDestroy 之後才會停止,這可以從上面的範例看出來,不管是透過 main queue 或者 workder thread 執行計算,都是從 onCreate 就啟動的,不是在 onStart 或者 onResume,有一個測試的方法就是將計算的筆數加大為100筆,並在 worker thread 的 loop 裡呼叫 Thread.sleep(...) 以延長執行時間,一旦 app 啟動後,可以跳回 Home 或上一頁來離開該 app,這時先在 log 看到 main thread 與 worker thread 都仍在執行,再跳回該 app,可以從頁面的計算過程得到證明,但是如果離開太久,該 app 是有可以被強制關閉(onDestroy)的。
由上可知,不可以在 onStart 或者 onResume 啟動 worker thread,否則每次離開再回來或者甚至螢幕轉個方向,就可能產生一個新的 worker thread,是可以用 instance var 來追蹤 thread 以迴避這樣的問題,不過一般 worker thread 的啟動應該是透過 user 的事件驅動,比較不會有這樣的問題發生,但是如果是有記憶的狀況,例如這次沒做完下次要繼續做或者在 app 一起動便要建立 worker thread 的話,那就得要在 onCreate 裡進行了。
最後,如果要中途停止 worker thread,不建議呼叫 Thread.stop(...) ,因為這樣沒辦法控制停止的方式,建議在 thread 裡加一個 flag,當必須終止時,只要更改 flag,讓 thread 可以優雅的打卡下班。
相關文章
訂閱:
文章 (Atom)
想不通怎麼做
可以請您大概舉個例子嗎?
可以拜託您大概舉個例子嗎
目前想不到
要怎麼做
謝謝^^
想不通怎麼做
可以請您大概舉個例子嗎?
// 保留住 wt 供稍後修改 stop
WorkerThread wt = new WorkerThread(intList, handler);
new Thread().start();
// 在 WorkerThread.run() 的迴圈裡
for (...) {
if (this.stop) {
break;
}
// ...
}
// 在某個地方,也許是使用者按下停止
wt.stop = true;