<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mr./Ms. Days (MMDays) - 網路, 資訊, 觀察, 生活MMDays &#8211; 作業系統</title>
	<atom:link href="http://mmdays.com/tag/%e4%bd%9c%e6%a5%ad%e7%b3%bb%e7%b5%b1/feed/" rel="self" type="application/rss+xml" />
	<link>http://mmdays.com</link>
	<description>網路, 產業, 資訊, 觀察, 生活, 電影, 技術, 新知, 科技, 媒體, 趨勢, Web 2.0</description>
	<lastBuildDate>Thu, 24 May 2012 16:59:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>千頭萬緒：平行計算和吃飯中的哲學家</title>
		<link>http://mmdays.com/2007/06/12/dining_philosopher-2/</link>
		<comments>http://mmdays.com/2007/06/12/dining_philosopher-2/#comments</comments>
		<pubDate>Tue, 12 Jun 2007 15:55:37 +0000</pubDate>
		<dc:creator>Mr. Thursday</dc:creator>
				<category><![CDATA[Mr. Thursday]]></category>
		<category><![CDATA[專欄]]></category>
		<category><![CDATA[電腦科學]]></category>
		<category><![CDATA[作業系統]]></category>
		<category><![CDATA[哲學家]]></category>
		<category><![CDATA[平行計算]]></category>

		<guid isPermaLink="false">http://mmdays.com/2007/06/12/dining_philosopher/</guid>
		<description><![CDATA[第一個問題是工作的完整性 (atomic) 和同步性 (synchronization) 的問題。譬如說餐廳的訂位系統，訂位的步驟有兩步：(1) 查詢現在剩下的位子 (2) 如果有位子的話，就把位子訂下來，否則回覆沒有位子。這個演算法非常簡單，只有兩個步驟。如果今天我們想把這個系統用平行計算來處理，達到節省時間的效果，會發生甚麼事情呢？]]></description>
			<content:encoded><![CDATA[<p><strong>Posted By <font color="#008000">Mr. Thursday</font></strong></p>
<p>每天早上醒來，我們通常會洗臉刷牙，吃早餐，搭車上班或是上學。有時候我們為了節省時間，會開始「平行處理」，譬如說：我們一邊擠牙膏的時候，可能一邊開水龍頭把水裝滿，同時完成兩件事情，減少等待閒置的時間。這就是平行處理的一個例子。我們如果把工作分成兩部分，同時給兩台機器跑，那麼原來需要一小時的工作，現在就可以在半小時內完成了。以此類推，如果有n台機器，那麼就能以 n 倍的速度完成原來的工作。平行計算如此好，然而卻會遇到一些問題，同時也有新的問題會產生。</p>
<p>第一個問題是<strong>工作</strong>的<strong>完整性</strong> (atomic) 和<strong>同步性</strong> (synchronization) 的問題。譬如說餐廳的訂位系統，訂位的步驟有兩步：(1) 查詢現在剩下的位子 (2) 如果有位子的話，就把位子訂下來，否則回覆沒有位子。這個演算法非常簡單，只有兩個步驟。如果今天我們想把這個系統用平行計算來處理，達到節省時間的效果，會發生甚麼事情呢？</p>
<p><span id="more-4396"></span>首先，因為電腦的<strong>作業系統 </strong>(OS: Operating System) 要達到<strong>平行計算</strong>的效果，會把每一個獨立的運轉單位當成是一個<strong>執行緒</strong> (<strong>thread</strong>)，然而作業系統在一般情況下並不會限制執行緒的<strong>優先順序</strong> (priority)，因此這一堆執行緒可能依次執行，也可能第一個 thread 執行到一半，換到第二個 thread，之後再跳回第一個 thread 繼續跑完。</p>
<p>所以就上面這個例子，如果今天作業系統裡面有兩個執行緒，分別處理兩個同時要訂位的要求。第一個<font color="#ff0000">執行緒甲 </font>(thread) 先執行步驟 (1)，他發現餐廳剛好剩下最後一個位子，所以他準備要執行步驟 (2) 訂這個位子。接下來作業系統跳到第二個<font color="#800080">執行緒乙</font> (thread)，執行步驟 (1)，也發現有一個位子，所以準備執行步驟 (2) 訂位子。結果作業系統再分別把<font color="#ff0000">執行緒甲</font>和<font color="#800080">執行緒乙</font>跑完，發現一個位子被兩個人訂走了。到時候客人來的時候，就發現怎麼有<strong>兩位客人訂到同一個位子</strong>了！</p>
<p>同樣的情形也可能發生在提款和存款的系統。如果今天提款的步驟是：(1) 查詢餘額=X (2) 將餘額扣除領出來的錢數M (3) 把扣完的餘額存回原來帳戶的紀錄裡面，成為新的餘額，也就是 X-M。假如這個系統也用平行計算，現在又有兩個人在不同提款機提同一個帳戶的錢。<font color="#ff0000">thread A</font> 首先查詢餘額 100 元，然後扣掉提出來的 20 元，剩下<font color="#ff0000"> 80 元</font>，還沒更新紀錄之前，<font color="#800080">thread B </font>被作業系統選進來，查詢餘額又是 100 元，然後扣掉提出來的錢，假設這次他要提 30 元，剩下餘額應該是<font color="#800080"> 70 元</font>，接著把餘額寫回系統，變成餘額 70 元。作業系統再回到 <font color="#ff0000">thread A</font>，把剛才算出來的餘額寫回去，變成餘額 80 元。所以，兩個人總共提領了 20+30 = 50 元，帳戶餘額應該是 50 元，但是成是因為平行計算的原因，餘額變成 80 元，讓銀行白白被提領了 30 元！同樣的情形也可能讓帳戶少 30 元，讓銀行白白多了 30 元。無論是銀行少錢，或是存款人少錢，相信兩方都不會高興的！只有正確的餘額紀錄下來，才會讓銀行和存款者都滿意！</p>
<p>因此，如果一個程式要變成平行計算來增進效率，首先要確定某些步驟是<strong>完整</strong>的 (atomic)，有如原子不可分割一般。像是訂餐系統裡面的兩個步驟，必須確定要一次執行完，不能中途被作業系統打斷，改執行另外一個thread。提款系統中的步驟 (1)(2)(3) 也是要一次執行完，才不會發生餘額<strong>多錢或少錢</strong>的情形。然而完整的步驟，或是同步後的步驟，雖然可以避免錯誤的結果，卻減少了平行計算的效率，譬如說剛才假如有 100 個人訂位，那麼第一個人訂位的時候，剩下 99 個人就要等待，因為步驟 (1)(2) 要一次執行完，即使電腦有雙核心或 100 核心也沒辦法平行處理。這是一種 tradeoff，有的問題就是無法平行化；有的可以，但是要<strong>同步</strong> (synchronize) 某些步驟，犧牲部分<strong>效率</strong>上的延遲，以保證答案的<strong>正確</strong>。</p>
<p>第二個問題是<strong>死結</strong> (deadlock) 的問題。這個問題發生的最經典的例子，就是<strong>用餐中的哲學家</strong> (Dining Philosopher) 的問題。Dining Philosopher 的問題是這樣子的：有 n 位哲學家，假設有 8 位好了，他們每個人會有三個狀態：想問題 (think)、飢餓 (hungry)、以及吃飯 (eat)。這8個哲學家坐在一個圓桌上，環繞成一個圓圈，如下圖：</p>
<p align="center"><img src="http://mmdays.wordpress.com/files/2007/06/dp_2.gif" alt="Dining_Philosopher" /></p>
<p>每個哲學家的左手和右手各有一根筷子，當哲學家飢餓的時候，就會試著拿起兩邊的筷子，兩邊的筷子都拿到了，才能開始吃 (eat)，否則就維持在飢餓狀態。這 8 位哲學家就是 8 個執行緒 (thread)，各自被作業系統安排執行，沒有固定的先後順序，也不知道會吃多久。那麼我們要怎樣子為每一位哲學家設計演算法步驟，才能讓所有哲學家都能夠吃到飯，沒有人會餓死，也沒有人每次都拿不到筷子呢？</p>
<p>第一個方法可能是：我們讓每一位哲學家<strong>先拿起右手邊的筷子</strong>，拿不到就<strong>等</strong>。拿到右手邊筷子之後，再等左手邊拿到筷子。兩邊筷子都拿到了就開始吃飯，吃完再放下筷子。但是這個演算法有一個問題，就是<strong>死結</strong> (deadlock)。假設作業系統先跑第一位哲學家，第一位拿起右手邊的筷子，接著執行第二位哲學家，第二位哲學家拿起右邊的筷子，再跑第三位哲學家，以此類推，最後 8 位哲學家都拿到右手邊的筷子，然後都在等左手邊的筷子，這個時候就變成 deadlock 了，因為每個人左手邊的筷子，都被另一個哲學家當成右邊的筷子拿起來了，而另一位哲學家還要等其他哲學家放下筷子，才可能把他手中的筷子放下，第一位哲學家才有機會拿到他左手邊的筷子。因此這8位哲學家就會等在那邊，永遠沒辦法用餐了！</p>
<p>另外一個 deadlock 的例子是這樣子的：某一個地方規定在十字路口上，如果兩條路上面剛好有兩部車到這個路口，那麼「<u>兩部車都要先停下來，等對方通過以後，再開過去</u>」。這個規定聽起來似乎不錯，還有<strong>禮讓</strong>的味道。然而這個演算法會造成deadlock，因為兩部車都停下來，然後都等對方通過，但是兩部車都不會開動，彼此<strong>等來等去</strong>，最後一直等都沒辦法開動了！</p>
<p>剛才的 8 位哲學家也是這個問題，每一位哲學家都要等待另一位哲學家，而另一位哲學家要繼續等待另一位哲學家，最後<strong>等到我自己</strong>，形成一個<strong>等待的迴路</strong>，就永遠等不完了。</p>
<p>為了解決這個問題，我們可能想出第二個演算法：先拿<strong>右邊的筷子</strong>，如果左邊筷子等不到，那麼就把右邊筷子<strong>放下</strong>，這樣子至少右邊的哲學家有機會拿到他左手邊的筷子，他吃完我就有機會再拿到筷子了！這樣子似乎不錯，然而會造成 <strong>livelock </strong>(活結)，也就是說，這8位哲學家不會無限地等下去，但是卻有可能<strong>不斷地拿起筷子又放下筷子</strong>，最後都沒有吃到飯。為甚麼呢？假設今天作業系統讓第一位哲學家先拿右邊的筷子、第二位拿右邊的筷子、以此類推、到第 8 位拿起右手邊的筷子。因為等不到左手邊的筷子，所以從第 8 位開始，放下右手邊的筷子、第七位放下右手邊的筷子、到最後第一位哲學家也放下右手邊的筷子。如此一來，大家都先拿起右手邊的筷子，然後又放下右手邊的筷子，但是都沒有吃到飯。這就是 livelock 了！(上面那張圖就是 livelock 的例子)</p>
<p>也許會說，如果剛才第8位拿到右邊的筷子後，第一位哲學家先放下右手邊的筷子，因為圓桌的關係，第一位右手邊的筷子就是第 8 位左手邊的筷子，那麼第 8 位哲學家就能順利吃到飯了！接下來第 7 位也可以順利吃到飯了，以此類推。然而平行計算有個特點，就是作業系統的排程是不確定的，每一個執行緒thread並沒有優先順序之分 (除非例外情形或是作業系統本身的工作)，因此我們<strong>各種執行順序</strong>的可能性都要考慮到。這也就是說，我們如果要設計一個可以平行處理的演算法，必須要考慮<strong>所有可能執行的順序和情況</strong>，確定這些情況下我們的演算法都<strong>對</strong>，才是對的演算法。這邊的「對」包括了<u>結果正確</u>，以及不會造成 <u>deadlock </u>(<strong>死結</strong>)、<u>livelock</u> (<strong>活結</strong>)、或是有時候還會有<strong>飢饉 </strong>(<u>starving</u>) 的情況。</p>
<p>最後提供一下名詞的區辨。<strong><font color="#0000ff">多執行緒</font></strong>是指同一個電腦為了達成<strong>多工</strong> (multi-tasking)，讓 CPU 可以跑多個執行緒 (thread)，執行的順序和時間長短由<strong>作業系統</strong>來做<strong>排程 </strong>(scheduling)。<strong><font color="#0000ff">平行計算</font></strong>可以發生在單一 CPU 或多個 CPU 的機器上面，只要演算法是可以平行處理完某件工作就是平行演算法。<strong><font color="#0000ff">分散式處理</font></strong>則是指「多個電腦」一起處理事情，和「多個 CPU」不同的地方在於<strong>記憶體</strong>沒有共享，電腦之間的溝通必須透過<strong>網路</strong>來傳遞訊息和資料。<strong><font color="#0000ff">P2P</font></strong> (peer-to-peer) 也是一種分散式處理，只不過他強調的是電腦之間的關係，是平等的架構，而不是主從式 (server-client) 架構，有提供資料的<strong>主機</strong> (server) 和享受資料的<strong>客戶端</strong> (client)，每台電腦同時是提供資料的主機 (server) 和享受資料的客戶端 (client)，沒有主人和僕人的區別，因此稱為<strong>同儕</strong> (peer)，整個網路就稱為同儕網路了 (peer-to-peer)。</p>
<p>參考資料</p>
<ul>
<li>(Wikipedia)<a href="http://en.wikipedia.org/wiki/Dining_philosophers" target="_blank">Dining Philosophers</a></li>
<li><a href="http://users.erols.com/ziring/diningAppletDemo.html" target="_blank">Dining Philosophers Java Applet</a></li>
</ul>
<p><br/>
<div>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td><a href="http://plurktop.mmdays.com/replurkdetail/?link=07233815946a0c51037b1e1d85aed1c6" title="看看其他人討論內容" target="_blank"><img src="http://plurktop.mmdays.com/images/replurk_1.png" style="border:0"></a></td>
</tr>
<tr>
<td><a href="http://plurk.com/?qulaifier=shares&#038;status=http%3A%2F%2Fmmdays.com%2F2007%2F06%2F12%2Fdining_philosopher-2%2F+%28%E5%8D%83%E9%A0%AD%E8%90%AC%E7%B7%92%EF%BC%9A%E5%B9%B3%E8%A1%8C%E8%A8%88%E7%AE%97%E5%92%8C%E5%90%83%E9%A3%AF%E4%B8%AD%E7%9A%84%E5%93%B2%E5%AD%B8%E5%AE%B6%29+-+%E8%BD%89%E5%99%97%E6%8E%92%E8%A1%8C%E6%A6%9C+http%3A%2F%2Fplurktop.mmdays.com%2Freplurk" title="推到噗浪" target="_blank"><img style="border:0" src="http://plurktop.mmdays.com/images/replurk_2.png" /></a></td>
</tr>
</table>
</div>
<p><br/><a href="http://www.facebook.com/MMDays" target="_blank">加入MMDays在facebook的粉絲團 隨時閱讀最新文章</a><br/></p>
]]></content:encoded>
			<wfw:commentRss>http://mmdays.com/2007/06/12/dining_philosopher-2/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
	</channel>
</rss>

