問題來源
非常感謝@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><div></code>
<code> </code><code></div></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<warehouse> split(work work, list<worker> workers)</code><code>throws</code> <code>remoteexception {</code>
<code> </code><code>list<warehouse> list =</code><code>new</code> <code>arraylist<warehouse>();</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 <</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><span></span> <span></span>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 - 線程組<id:4af96b81d14a4954a6b649308d444e4c,type:second>運作開始,線程數</code><code>9</code><code>...</code>
<code>-</code><code>234</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-a763f156ffd74b5db285198d2498edcf] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-a763f156ffd74b5db285198d2498edcf>運作開始...</code>
<code>-</code><code>234</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-c2d2fb38ef6c4509b3a39b3e7d5c1d61] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-c2d2fb38ef6c4509b3a39b3e7d5c1d61>運作開始...</code>
<code>-</code><code>234</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-d624ea0a6df3409c80df6b97ab3c813b] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-d624ea0a6df3409c80df6b97ab3c813b>運作開始...</code>
<code>-</code><code>235</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-abdb57f0641a4727a9efa744d07cf2d1] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-abdb57f0641a4727a9efa744d07cf2d1>運作開始...</code>
<code>-</code><code>236</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-d6f7074f6c4a4b12bd37ec5f5c11aff8] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-d6f7074f6c4a4b12bd37ec5f5c11aff8>運作開始...</code>
<code>-</code><code>237</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-04db3f945b804500a2bbe2b9aabdce3b] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-04db3f945b804500a2bbe2b9aabdce3b>運作開始...</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 - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-a763f156ffd74b5db285198d2498edcf>運作結束</code>
<code>-</code><code>246</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-f3efba2dc7804c6cbcd5a25f42fdc177] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-f3efba2dc7804c6cbcd5a25f42fdc177>運作開始...</code>
<code>-</code><code>246</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-abdb57f0641a4727a9efa744d07cf2d1] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-abdb57f0641a4727a9efa744d07cf2d1>運作結束</code>
<code>-</code><code>248</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-8c3b9359bcfa4de7b6e0492daab0d73a] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-8c3b9359bcfa4de7b6e0492daab0d73a>運作開始...</code>
<code>tyre is ok</code>
<code>-</code><code>250</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-f3efba2dc7804c6cbcd5a25f42fdc177] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-f3efba2dc7804c6cbcd5a25f42fdc177>運作結束</code>
<code>-</code><code>250</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-c2d2fb38ef6c4509b3a39b3e7d5c1d61] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-c2d2fb38ef6c4509b3a39b3e7d5c1d61>運作結束</code>
<code>-</code><code>252</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-869b573e226046aca8ad30765f1f300c] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-869b573e226046aca8ad30765f1f300c>運作開始...</code>
<code>-</code><code>253</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-8c3b9359bcfa4de7b6e0492daab0d73a] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-8c3b9359bcfa4de7b6e0492daab0d73a>運作結束</code>
<code>-</code><code>257</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-d624ea0a6df3409c80df6b97ab3c813b] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-d624ea0a6df3409c80df6b97ab3c813b>運作結束</code>
<code>-</code><code>258</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-04db3f945b804500a2bbe2b9aabdce3b] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-04db3f945b804500a2bbe2b9aabdce3b>運作結束</code>
<code>-</code><code>262</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-869b573e226046aca8ad30765f1f300c] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-869b573e226046aca8ad30765f1f300c>運作結束</code>
<code>-</code><code>264</code> <code>[id:4af96b81d14a4954a6b649308d444e4c,type:second-d6f7074f6c4a4b12bd37ec5f5c11aff8] info - 線程<id:4af96b81d14a4954a6b649308d444e4c,type:second-d6f7074f6c4a4b12bd37ec5f5c11aff8>運作結束</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 - 線程組<id:4af96b81d14a4954a6b649308d444e4c,type:second>運作結束, 用時: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 - 線程組<id:9b0de678632d4fb8b87ae9db4b6436f8,type:third>運作開始,線程數</code><code>5</code><code>...</code>
<code>-</code><code>334</code> <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-ca58e9b733514c668a224875417c9d26] info - 線程<id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-ca58e9b733514c668a224875417c9d26>運作開始...</code>
<code>-</code><code>334</code> <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-17debef817e34c49996a2c38840f3de2] info - 線程<id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-17debef817e34c49996a2c38840f3de2>運作開始...</code>
<code>-</code><code>334</code> <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-af0e914cce89480987c6184a885770d5] info - 線程<id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-af0e914cce89480987c6184a885770d5>運作開始...</code>
<code>-</code><code>334</code> <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-3f7707cb2a224d3d8844a09271b24a07] info - 線程<id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-3f7707cb2a224d3d8844a09271b24a07>運作開始...</code>
<code>door is ok</code>
<code>-</code><code>338</code> <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-ca58e9b733514c668a224875417c9d26] info - 線程<id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-ca58e9b733514c668a224875417c9d26>運作結束</code>
<code>-</code><code>339</code> <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-cfccfb37ebda4279b7552f7e060b2ddb] info - 線程<id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-cfccfb37ebda4279b7552f7e060b2ddb>運作開始...</code>
<code>-</code><code>338</code> <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-17debef817e34c49996a2c38840f3de2] info - 線程<id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-17debef817e34c49996a2c38840f3de2>運作結束</code>
<code>-</code><code>340</code> <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-3f7707cb2a224d3d8844a09271b24a07] info - 線程<id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-3f7707cb2a224d3d8844a09271b24a07>運作結束</code>
<code>roof is ok</code>
<code>-</code><code>340</code> <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-af0e914cce89480987c6184a885770d5] info - 線程<id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-af0e914cce89480987c6184a885770d5>運作結束</code>
<code>-</code><code>342</code> <code>[id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-cfccfb37ebda4279b7552f7e060b2ddb] info - 線程<id:9b0de678632d4fb8b87ae9db4b6436f8,type:third-cfccfb37ebda4279b7552f7e060b2ddb>運作結束</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 - 線程組<id:9b0de678632d4fb8b87ae9db4b6436f8,type:third>運作結束, 用時:10ms</code>
從上面的日志可以看出:
由于第一步工作是挑一個單幹的,是以是沒有啟用線程組的
第二步同時有9個線程幹活:
<code>...</code>
第三步同時有5個線程幹活:
總結:
tiny并行計算架構确實是可以友善的解決各種複雜并行計算的問題。