天天看點

Tiny并行計算架構之複雜示例

問題來源

非常感謝@doctorwho的問題:

假如職業介紹所來了一批生産汽車的工作,假設生産一輛汽車任務是這樣的:搭好底盤、擰4個輪胎、安裝發動機、安裝4個座椅、再裝4個車門、最後安裝頂棚。之間有的任務是可以并行計算的(比如擰4個輪胎,安裝發動機和安裝座椅),有的任務有前置任務(比如先裝好座椅,才能裝車門和頂棚)。讓兩組包工頭組織兩種類型的工作:将勞工分成兩種類型,即可并行計算的放在同一組内,由職業介紹所來控制a組包工頭做完的任務交給b組包工頭。中間環節的半成品儲存到warehouse中,是這樣使用tiny架構來生産汽車麼?

接下來,我就用tiny并行計算架構來展示一下這個示例,在編寫示例的時候,發現了一個bug,這也充分展現了開源的精神與價值,再次感謝@doctorwho。

問題分析

doctorwho的問題還是比較複雜的,但是實際上道理是一樣的,是以我把問題簡化成下面的過程

第一步:建構底盤

第二步:并行進行安裝引擎,座位和輪胎

第三步:并行進行安裝門及車頂

由于我和doctorwho都不是造車行家,是以就不用糾結這麼造是不是合理了,假設這麼做就是合理的。

代碼實作

按我前面說的過程,勞工是必須要有的,是以我們首先建構勞工:

第一步的底盤建構勞工

<a href="http://my.oschina.net/tinyframework/blog/196486#">?</a>

1

2

3

4

5

6

7

8

9

10

11

12

13

<code>public</code> <code>class</code> <code>stepfirstworker</code><code>extends</code> <code>abstractworker {</code>

<code>    </code><code>public</code> <code>stepfirstworker()</code><code>throws</code> <code>remoteexception {</code>

<code>        </code><code>super</code><code>(</code><code>"first"</code><code>);</code>

<code>    </code><code>}</code>

<code>    </code><code>@override</code>

<code>    </code><code>protected</code> <code>warehouse dowork(work work)</code><code>throws</code> <code>remoteexception {</code>

<code>        </code><code>system.out.println(string.format(</code><code>"%s 建構底盤完成."</code><code>, work.getinputwarehouse().get(</code><code>"cartype"</code><code>)));</code>

<code>        </code><code>warehouse outputwarehouse = work.getinputwarehouse();</code>

<code>        </code><code>outputwarehouse.put(</code><code>"baseinfo"</code><code>,</code><code>"something about baseinfo"</code><code>);</code>

<code>        </code><code>return</code> <code>outputwarehouse;</code>

<code>}</code>

由于第二步勞工有好幾個類型,是以再搞個第二步抽象勞工:

14

15

16

17

18

19

<code>public</code> <code>abstract</code> <code>class</code> <code>stepthirdworker</code><code>extends</code> <code>abstractworker {</code>

<code>   </code><code>public</code> <code>stepthirdworker()</code><code>throws</code> <code>remoteexception {</code>

<code>       </code><code>super</code><code>(</code><code>"third"</code><code>);</code>

<code>   </code><code>}</code>

<code>   </code><code>protected</code> <code>boolean</code> <code>acceptmywork(work work) {</code>

<code>       </code><code>string workclass = work.getinputwarehouse().get(</code><code>"class"</code><code>);</code>

<code>       </code><code>if</code> <code>(workclass !=</code><code>null</code><code>) {</code>

<code>           </code><code>return</code> <code>true</code><code>;</code>

<code>       </code><code>}</code>

<code>       </code><code>return</code> <code>false</code><code>;</code>

<code>   </code><code>protected</code> <code>warehouse domywork(work work)</code><code>throws</code> <code>remoteexception {</code>

<code>       </code><code>system.out.println(string.format(</code><code>"base:%s "</code><code>, work.getinputwarehouse().get(</code><code>"baseinfo"</code><code>)));</code>

<code>       </code><code>system.out.println(string.format(</code><code>"%s is ok"</code><code>, work.getinputwarehouse().get(</code><code>"class"</code><code>)));</code>

<code>       </code><code>return</code> <code>work.getinputwarehouse();</code>

接下來建構第二步的引擎勞工:

20

<code>public</code> <code>class</code> <code>stepsecondengineworker</code><code>extends</code> <code>stepsecondworker {</code>

<code> </code><code>public</code> <code>static</code> <code>final</code> <code>string engine =</code><code>"engine"</code><code>;</code>

<code> </code><code>public</code> <code>stepsecondengineworker()</code><code>throws</code> <code>remoteexception {</code>

<code> </code><code>super</code><code>();</code>

<code> </code><code>}</code>

<code> </code><code>public</code> <code>boolean</code> <code>acceptwork(work work) {</code>

<code> </code><code>return</code> <code>acceptmywork(work);</code>

<code> </code><code>protected</code> <code>warehouse dowork(work work)</code><code>throws</code> <code>remoteexception {</code>

<code> </code><code>return</code> <code>super</code><code>.domywork(work);</code>

第二步的座位勞工:

21

<code>public</code> <code>class</code> <code>stepsecondseatworker</code><code>extends</code> <code>stepsecondworker {</code>

<code>   </code><code>public</code> <code>static</code> <code>final</code> <code>string seat =</code><code>"seat"</code><code>;</code>

<code>   </code><code>public</code> <code>stepsecondseatworker()</code><code>throws</code> <code>remoteexception {</code>

<code>       </code><code>super</code><code>();</code>

<code>   </code><code>public</code> <code>boolean</code> <code>acceptwork(work work) {</code>

<code>       </code><code>return</code> <code>acceptmywork(work);</code>

<code>   </code><code>protected</code> <code>warehouse dowork(work work)</code><code>throws</code> <code>remoteexception {</code>

<code>       </code><code>return</code> <code>super</code><code>.domywork(work);</code>

<code> </code><code>&lt;div&gt;</code>

<code> </code><code>&lt;/div&gt;</code>

第二步的輪胎勞工:

<code>public</code> <code>class</code> <code>stepsecondtyreworker</code><code>extends</code> <code>stepsecondworker {</code>

<code> </code><code>public</code> <code>static</code> <code>final</code> <code>string tyre =</code><code>"tyre"</code><code>;</code>

<code> </code><code>public</code> <code>stepsecondtyreworker()</code><code>throws</code> <code>remoteexception {</code>

同理,第三步也是大同小異的。

第三步的抽象勞工類:

第三步的車門勞工:

<code>public</code> <code>class</code> <code>stepthirddoorworker</code><code>extends</code> <code>stepthirdworker {</code>

<code>   </code><code>public</code> <code>static</code> <code>final</code> <code>string door =</code><code>"door"</code><code>;</code>

<code>   </code><code>public</code> <code>stepthirddoorworker()</code><code>throws</code> <code>remoteexception {</code>

<code>   </code><code>@override</code>

第三步的車頂勞工:

<code>public</code> <code>class</code> <code>stepthirdroofworker</code><code>extends</code> <code>stepthirdworker {</code>

<code>   </code><code>public</code> <code>static</code> <code>final</code> <code>string roof =</code><code>"roof"</code><code>;</code>

<code>   </code><code>public</code> <code>stepthirdroofworker()</code><code>throws</code> <code>remoteexception {</code>

以上就把勞工都建構好了,我們前面也說過,如果要進行任務分解,是必須要建構任務分解合并器的,這裡簡單起見,隻實作任務分解了。

第二部的任務分解:

22

<code>public</code> <code>class</code> <code>secondworksplitter</code><code>implements</code> <code>worksplitter {</code>

<code>    </code><code>public</code> <code>list&lt;warehouse&gt; split(work work, list&lt;worker&gt; workers)</code><code>throws</code> <code>remoteexception {</code>

<code>        </code><code>list&lt;warehouse&gt; list =</code><code>new</code> <code>arraylist&lt;warehouse&gt;();</code>

<code>        </code><code>list.add(getwarehouse(work.getinputwarehouse(),</code><code>"engine"</code><code>));</code>

<code>        </code><code>list.add(getwarehouse(work.getinputwarehouse(),</code><code>"seat"</code><code>));</code>

<code>        </code><code>list.add(getwarehouse(work.getinputwarehouse(),</code><code>"tyre"</code><code>));</code>

<code>        </code><code>return</code> <code>list;</code>

<code>    </code><code>private</code> <code>warehouse getwarehouse(warehouse inputwarehouse, string stepclass) {</code>

<code>        </code><code>warehouse warehouse =</code><code>new</code> <code>warehousedefault();</code>

<code>        </code><code>warehouse.put(</code><code>"class"</code><code>, stepclass);</code>

<code>        </code><code>warehouse.putsubwarehouse(inputwarehouse);</code>

<code>        </code><code>return</code> <code>warehouse;</code>

從上面可以看到,建構了一個引擎的倉庫,4個座位倉庫,4個輪胎倉庫。呵呵,既然能并行,為啥不讓他做得更快些?

接下來是第三步的任務分解器:

<code>public</code> <code>class</code> <code>thirdworksplitter</code><code>implements</code> <code>worksplitter {</code>

<code>        </code><code>list.add(getwarehouse(work.getinputwarehouse(),</code><code>"door"</code><code>));</code>

<code>        </code><code>list.add(getwarehouse(work.getinputwarehouse(),</code><code>"roof"</code><code>));</code>

從上面可以看到,第三部建構了4個門倉庫一個車頂倉庫,同樣的,可以讓4個勞工同時裝門。

上面就把所有的準備工作都做好了,接下來就是測試方法了:

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

<code>public</code> <code>class</code> <code>test {</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(string[] args)</code><code>throws</code> <code>ioexception, classnotfoundexception, interruptedexception {</code>

<code>        </code><code>jobcenter jobcenter =</code><code>new</code> <code>jobcenterlocal();</code>

<code>        </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i &lt;</code><code>5</code><code>; i++) {</code>

<code>            </code><code>jobcenter.registerworker(</code><code>new</code> <code>stepfirstworker());</code>

<code>        </code><code>}</code>

<code>            </code><code>jobcenter.registerworker(</code><code>new</code> <code>stepsecondtyreworker());</code>

<code>            </code><code>jobcenter.registerworker(</code><code>new</code> <code>stepsecondseatworker());</code>

<code>            </code><code>jobcenter.registerworker(</code><code>new</code> <code>stepsecondengineworker());</code>

<code>            </code><code>jobcenter.registerworker(</code><code>new</code> <code>stepthirddoorworker());</code>

<code>            </code><code>jobcenter.registerworker(</code><code>new</code> <code>stepthirdroofworker());</code>

<code>        </code><code>jobcenter.registerforeman(</code><code>new</code> <code>foremanselectoneworker(</code><code>"first"</code><code>));</code>

<code>     </code><code>&lt;span&gt;&lt;/span&gt; &lt;span&gt;&lt;/span&gt;jobcenter.registerforeman(</code><code>new</code> <code>foremanselectallworker(</code><code>"second"</code><code>,</code>

<code> </code><code>new</code> <code>secondworksplitter()));</code>

<code> </code><code>jobcenter.registerforeman(</code><code>new</code> <code>foremanselectallworker(</code><code>"third"</code><code>,</code><code>new</code> <code>thirdworksplitter()));</code>

<code> </code><code>warehouse inputwarehouse =</code><code>new</code> <code>warehousedefault();</code>

<code> </code><code>inputwarehouse.put(</code><code>"class"</code><code>,</code><code>"car"</code><code>);</code>

<code> </code><code>inputwarehouse.put(</code><code>"cartype"</code><code>,</code><code>"普桑"</code><code>);</code>

<code> </code><code>workdefault work =</code><code>new</code> <code>workdefault(</code><code>"first"</code><code>, inputwarehouse);</code>

<code> </code><code>work.setforemantype(</code><code>"first"</code><code>);</code>

<code> </code><code>workdefault work2 =</code><code>new</code> <code>workdefault(</code><code>"second"</code><code>);</code>

<code> </code><code>work2.setforemantype(</code><code>"second"</code><code>);</code>

<code> </code><code>workdefault work3 =</code><code>new</code> <code>workdefault(</code><code>"third"</code><code>);</code>

<code> </code><code>work3.setforemantype(</code><code>"third"</code><code>);</code>

<code> </code><code>work.setnextwork(work2).setnextwork(work3);</code>

<code> </code><code>warehouse warehouse = jobcenter.dowork(work);</code>

<code> </code><code>jobcenter.stop();</code>

呵呵,勞工各加了5個,然後注冊了三個工頭,第一步的工頭是随便挑一個勞工類型的,第二步和第三步是挑所有勞工的,同時還指定了任務分解器。

接下來就建構了一個工作,造一個高端大氣上檔次的普桑汽車,然後告訴職業介紹所說給我造就可以了。

下面是造車的過程,我把日志也貼上來了:

50

51

52

53

54

55

56

57

58

59

60

61

<code>普桑 建構底盤完成.</code>

<code>-</code><code>234</code>  <code>[rmi tcp connection(</code><code>1</code><code>)-</code><code>192.168</code><code>.</code><code>84.73</code><code>] info   - 線程組&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second&gt;運作開始,線程數</code><code>9</code><code>...</code>

<code>-</code><code>234</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-a763f156ffd74b5db285198d2498edcf] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-a763f156ffd74b5db285198d2498edcf&gt;運作開始...</code>

<code>-</code><code>234</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-c2d2fb38ef6c4509b3a39b3e7d5c1d61] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-c2d2fb38ef6c4509b3a39b3e7d5c1d61&gt;運作開始...</code>

<code>-</code><code>234</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-d624ea0a6df3409c80df6b97ab3c813b] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-d624ea0a6df3409c80df6b97ab3c813b&gt;運作開始...</code>

<code>-</code><code>235</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-abdb57f0641a4727a9efa744d07cf2d1] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-abdb57f0641a4727a9efa744d07cf2d1&gt;運作開始...</code>

<code>-</code><code>236</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-d6f7074f6c4a4b12bd37ec5f5c11aff8] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-d6f7074f6c4a4b12bd37ec5f5c11aff8&gt;運作開始...</code>

<code>-</code><code>237</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-04db3f945b804500a2bbe2b9aabdce3b] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-04db3f945b804500a2bbe2b9aabdce3b&gt;運作開始...</code>

<code>base:something about baseinfo</code>

<code>engine is ok</code>

<code>seat is ok</code>

<code>-</code><code>245</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-a763f156ffd74b5db285198d2498edcf] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-a763f156ffd74b5db285198d2498edcf&gt;運作結束</code>

<code>-</code><code>246</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-f3efba2dc7804c6cbcd5a25f42fdc177] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-f3efba2dc7804c6cbcd5a25f42fdc177&gt;運作開始...</code>

<code>-</code><code>246</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-abdb57f0641a4727a9efa744d07cf2d1] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-abdb57f0641a4727a9efa744d07cf2d1&gt;運作結束</code>

<code>-</code><code>248</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-8c3b9359bcfa4de7b6e0492daab0d73a] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-8c3b9359bcfa4de7b6e0492daab0d73a&gt;運作開始...</code>

<code>tyre is ok</code>

<code>-</code><code>250</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-f3efba2dc7804c6cbcd5a25f42fdc177] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-f3efba2dc7804c6cbcd5a25f42fdc177&gt;運作結束</code>

<code>-</code><code>250</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-c2d2fb38ef6c4509b3a39b3e7d5c1d61] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-c2d2fb38ef6c4509b3a39b3e7d5c1d61&gt;運作結束</code>

<code>-</code><code>252</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-869b573e226046aca8ad30765f1f300c] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-869b573e226046aca8ad30765f1f300c&gt;運作開始...</code>

<code>-</code><code>253</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-8c3b9359bcfa4de7b6e0492daab0d73a] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-8c3b9359bcfa4de7b6e0492daab0d73a&gt;運作結束</code>

<code>-</code><code>257</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-d624ea0a6df3409c80df6b97ab3c813b] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-d624ea0a6df3409c80df6b97ab3c813b&gt;運作結束</code>

<code>-</code><code>258</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-04db3f945b804500a2bbe2b9aabdce3b] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-04db3f945b804500a2bbe2b9aabdce3b&gt;運作結束</code>

<code>-</code><code>262</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-869b573e226046aca8ad30765f1f300c] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-869b573e226046aca8ad30765f1f300c&gt;運作結束</code>

<code>-</code><code>264</code>  <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-d6f7074f6c4a4b12bd37ec5f5c11aff8] info   - 線程&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second-d6f7074f6c4a4b12bd37ec5f5c11aff8&gt;運作結束</code>

<code>-</code><code>264</code>  <code>[rmi tcp connection(</code><code>1</code><code>)-</code><code>192.168</code><code>.</code><code>84.73</code><code>] info   - 線程組&lt;id:4af96b81d14a4954a6b649308d444e4c,type:second&gt;運作結束, 用時:30ms</code>

<code>-</code><code>333</code>  <code>[rmi tcp connection(</code><code>1</code><code>)-</code><code>192.168</code><code>.</code><code>84.73</code><code>] info   - 線程組&lt;id:9b0de678632d4fb8b87ae9db4b6436f8,type:third&gt;運作開始,線程數</code><code>5</code><code>...</code>

<code>-</code><code>334</code>  <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-ca58e9b733514c668a224875417c9d26] info   - 線程&lt;id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-ca58e9b733514c668a224875417c9d26&gt;運作開始...</code>

<code>-</code><code>334</code>  <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-17debef817e34c49996a2c38840f3de2] info   - 線程&lt;id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-17debef817e34c49996a2c38840f3de2&gt;運作開始...</code>

<code>-</code><code>334</code>  <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-af0e914cce89480987c6184a885770d5] info   - 線程&lt;id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-af0e914cce89480987c6184a885770d5&gt;運作開始...</code>

<code>-</code><code>334</code>  <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-3f7707cb2a224d3d8844a09271b24a07] info   - 線程&lt;id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-3f7707cb2a224d3d8844a09271b24a07&gt;運作開始...</code>

<code>door is ok</code>

<code>-</code><code>338</code>  <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-ca58e9b733514c668a224875417c9d26] info   - 線程&lt;id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-ca58e9b733514c668a224875417c9d26&gt;運作結束</code>

<code>-</code><code>339</code>  <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-cfccfb37ebda4279b7552f7e060b2ddb] info   - 線程&lt;id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-cfccfb37ebda4279b7552f7e060b2ddb&gt;運作開始...</code>

<code>-</code><code>338</code>  <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-17debef817e34c49996a2c38840f3de2] info   - 線程&lt;id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-17debef817e34c49996a2c38840f3de2&gt;運作結束</code>

<code>-</code><code>340</code>  <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-3f7707cb2a224d3d8844a09271b24a07] info   - 線程&lt;id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-3f7707cb2a224d3d8844a09271b24a07&gt;運作結束</code>

<code>roof is ok</code>

<code>-</code><code>340</code>  <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-af0e914cce89480987c6184a885770d5] info   - 線程&lt;id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-af0e914cce89480987c6184a885770d5&gt;運作結束</code>

<code>-</code><code>342</code>  <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-cfccfb37ebda4279b7552f7e060b2ddb] info   - 線程&lt;id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-cfccfb37ebda4279b7552f7e060b2ddb&gt;運作結束</code>

<code>-</code><code>343</code>  <code>[rmi tcp connection(</code><code>1</code><code>)-</code><code>192.168</code><code>.</code><code>84.73</code><code>] info   - 線程組&lt;id:9b0de678632d4fb8b87ae9db4b6436f8,type:third&gt;運作結束, 用時:10ms</code>

從上面的日志可以看出:

由于第一步工作是挑一個單幹的,是以是沒有啟用線程組的

第二步同時有9個線程幹活:

<code>...</code>

第三步同時有5個線程幹活:

總結:

tiny并行計算架構确實是可以友善的解決各種複雜并行計算的問題。