WF本质论 OpenSesame 芝麻开门代码
本文參考了包建強兄的“WF本質論 讀書心得” (http://www.cnblogs.com/jax/archive/2008/02/21/1076632.html),他給出了部分的源代碼, 我修改了一點,再添加上他沒有給出的部分,就基本是一個可用的OpenSesame的源代碼了。
首先肯定,WF本質論是本不可多得的好書。作者提出了許多令人耳目一新的見解,重點是用bookmark(也就是continuation的概念)來把本來會耗時很長并無端占用線程的操作解耦,通過delegate轉換成可以在不同線程進程中執行的兩部分,也就是作者所謂的thread agility & process agility.
第一章應該是全書的關鍵,理解了第一章就為理解WF的內部機制打下了堅實的基礎。而作者用了一個貫穿了整個第一章例子,OpenSesame,芝麻開門來闡述他的觀點,建議所有的讀者都應該親自動手來實現一下這個OpenSesame的例子,絕對可以加深理解。可惜的是,作者沒有給出這個例子的完整代碼,這里缺一塊,那里少個角,掖著藏著讓人很不舒服。Google了一下也沒有全部的源碼,所以我覺得花點時間把這個芝麻開門的代碼寫出來很有必要。需要聲明的是,這個代碼絕對不是什么最終的或是官方的版本,只是到目前為止我對本書第一章的理解而已。只是供大家參考,希望可以給正在看“WF本質論”的朋友有所幫助。
個人感覺關鍵的地方有這幾點:
1)thread agility。 剛開始被書里的BeginReadLine例子誤導,總想著用BeginInvoke/EndInvoke去神奇的實現長耗時操作并不占用線程(比如實現Console.ReadLine),后來才發現作者不是這個意思。作者把一個長耗時操作分成了兩部分,上半部分(在代碼中就是ProgramStatement.Run方法)只是創建一個bookmark,就是設定一個delegate,并沒有其他的操作,也不需要異步,只是設定,然后上半部分就結束。下半部分(代碼中的ContinueAt)就是本操作在獲得了外界的輸入后應該做的動作。奧妙就在于本來需要由這個長耗時操作占用一個線程進行的漫長而又無用的等待的工作(比如Console.ReadLine,需要等待用戶輸入),現在可以由主線程提供通知,從而使長耗時操作的下半部分得以進行下去。這樣的好處就是,本來在等待輸入的過程中的是要有個線程的,而現在就沒了。
簡言之,大家可以這樣想,原先的情況是有一個主線程A,然后主線程A又生成了一個專門給長耗時操作用的線程B,在線程B里面需要Console.ReadLine,B得到輸入后會進行一些操作,這樣的話任何時候都會有兩個線程。如果用了bookmark的方法,主線程A產生線程B調用bookmark的上半部分,然后線程B結束,這時我們在主線程中進行Console.ReadLine,得到了輸入后我們再開一個線程B2,繼續bookmark下半部分的調用,這樣我們就節約了在等待用戶輸入時的一個線程。這就是作者所謂的thread agility。其實主線程是很忙的,實際運用中不可能停下來等待用戶輸入,它能做的應該是在它得到了用戶輸入/外界消息后(比如通過message queue),通知并調用bookmark的下半部分。
?2)書中的每個ProgramStatement(也就是WF的Activity)是通過BookmarkManager.Done()來啟動的。
3) Passivate是實現process agility的手段,在代碼中沒有實現。
4)Binding. 細心的讀者可能發現在書中作者沒有給出怎么把上個ProgramStatement的輸出賦值給下個ProgramStatement的代碼,作者狡猾的用省略號表示了。因為這個綁定的動作發生在ProgramStatement實際的執行以前,如果我們沒有做特殊處理的話,在執行的時候我們會得到null reference exception。在代碼中就是PrintGreeting的Run方法內。在運行本程序的時候你會發現無論你輸入什么,你總是得到"OKOK",因為我偷懶,沒有用特殊方法去處理。我想到的一個不破壞整個bookmark邏輯的處理方法就是用.net AOP,在PrintGreeting的key和s屬性上加上特殊的attribute,這樣當這兩個屬性需要被用到的時候會去另外的ProgramStatement(Read,PrintKey)取。
5)主線程內,當有了Console.ReadLine的輸入后,通過BookmarkManager.Resume去繼續Bookmark的下半部的執行。相當于WF中,用WorkflowInstance.EnqueueItem()去繼續流程。
6)ProgramHandle類,我覺得這個類有點雞肋,沒什么存在的必要。
?
附上OpenSesame的代碼,歡迎大家共同討論。
Codeusing?System;
using?System.Collections.Generic;
using?System.Threading;
namespace?OpenSesame
{
????public?delegate?void?BookmarkLocation(Bookmark?resumed);
????[Serializable]
????public?class?Bookmark
????{
????????public?Bookmark(string?name,?BookmarkLocation?continueAt)
????????{
????????????Name?=?name;
????????????ContinueAt?=?continueAt;
????????}
????????public?string?Name?{?get;?set;?}
????????public?BookmarkLocation?ContinueAt?{?get;?set;?}
????????public?object?Payload?{?get;?set;?}
????????public?BookmarkManager?BookmarkManager?{?get;?set;?}
????}
????public?class?BookmarkManager
????{
????????private?List<Bookmark>?bookmarkList;
????????private?ProgramStatement?currentProgramStatement;
????????public?BookmarkManager()
????????{
????????????bookmarkList?=?new?List<Bookmark>();
????????}
????????public?void?Add(Bookmark?bookmark)
????????{
????????????bookmarkList.Add(bookmark);
????????????bookmark.BookmarkManager?=?this;
????????}
????????public?void?Remove(Bookmark?bookmark)
????????{
????????????bookmarkList.Remove(bookmark);
????????}
????????public?void?Resume(string?bookmarkName,?object?payload)
????????{
????????????foreach?(Bookmark?bookmark?in?bookmarkList)
????????????{
????????????????if?(bookmark.Name?==?bookmarkName)
????????????????{
????????????????????bookmark.Payload?=?payload;
????????????????????bookmark.ContinueAt(bookmark);
????????????????????break;
????????????????}
????????????}
????????}
????????//?Request?execution?of?a?program?statement,?using?an
????????//?implicit?bookmark?that?will?be?resumed?when?that
????????//?program?statement?completes?its?execution
????????public?void?RunProgramStatement(ProgramStatement?statement,?BookmarkLocation?continueAt)
????????{
????????????currentProgramStatement?=?statement;
????????????Bookmark?bookmark?=?new?Bookmark(statement.GetType().FullName,?continueAt);
????????????Add(bookmark);
????????????statement.Run(this);
????????}
????????//?Indicate?that?the?current?program?statement?is?done,
????????//?so?that?internally?managed?bookmarks?can?be?resumed
????????public?void?Done(bool?bAllDone)
????????{
????????????if?(!bAllDone)
????????????????Resume(currentProgramStatement.GetType().FullName,?currentProgramStatement);
????????????else
????????????????bookmarkList.Clear();
????????}
????}
????[Serializable]
????public?abstract?class?ProgramStatement
????{
????????public?abstract?void?Run(BookmarkManager?mgr);
????}
????public?class?MythicalRuntime
????{
????????Dictionary<ProgramHandle,?ProgramStatement>?ht;
????????private?BookmarkManager?mgr?=?new?BookmarkManager();
????????public?MythicalRuntime()
????????{
????????????ht?=?new?Dictionary<ProgramHandle,?ProgramStatement>();
????????}
????????public?BookmarkManager?Mgr
????????{
????????????get?{?return?mgr;?}
????????????set?{?mgr?=?value;?}
????????}
????????public?ProgramHandle?RunProgram(ProgramStatement?program)
????????{
????????????//這個新的Guid根據規則創建,而不是簡單的new?Guid(),以下僅為模擬方法
????????????Guid?programId?=?new?Guid();
????????????ProgramHandle?programHandle?=?new?ProgramHandle();
????????????programHandle.ProgramId?=?programId;
????????????ht.Add(programHandle,?program);
????????????//Bookmark的上半部分,用新的thread執行
????????????ThreadPool.QueueUserWorkItem(state?=>?program.Run(state?as?BookmarkManager),?Mgr);
????????????return?programHandle;
????????}
????????public?ProgramHandle?GetProgramHandle(Guid?programId)
????????{
????????????//根據programId恢復已經鈍化的程序,假設恢復為read方法
????????????ProgramStatement?program?=?new?Read();
????????????//重新構建ProgramHandle
????????????ProgramHandle?programHandle?=?new?ProgramHandle();
????????????programHandle.ProgramId?=?programId;
????????????//重新加載到內存
????????????ht.Add(programHandle,?program);
????????????return?programHandle;
????????}
????????public?void?Shutdown()
????????{
????????????//從內存中取出所有ProgramHandle,?依次鈍化
????????????foreach?(ProgramHandle?tmpProgramHandle?in?ht.Keys)
????????????{
????????????????ProgramStatement?program?=?ht[tmpProgramHandle];
????????????????tmpProgramHandle.Passivate(program);
????????????}
????????????ht?=?null;
????????}
????}
????public?class?ProgramHandle
????{
????????private?Guid?programId;
????????public?Guid?ProgramId
????????{
????????????get?{?return?programId;?}
????????????set?{?programId?=?value;?}
????????}
????????public?void?Passivate(ProgramStatement?program)
????????{
????????????//將program根據關鍵字programId進行鈍化
????????}
????????public?void?Resume(string?bookmarkName,?object?payload)
????????{
????????????BookmarkManager?mgr?=?new?BookmarkManager();
????????????mgr.Resume(bookmarkName,?payload);
????????}
????}
????[Serializable]
????public?class?Read?:?ProgramStatement
????{
????????private?string?text;
????????public?string?Text
????????{
????????????get?{?return?text;?}
????????}
????????public?override?void?Run(BookmarkManager?mgr)
????????{
????????????mgr.Add(new?Bookmark("read",?ContinueAt));
????????}
????????void?ContinueAt(Bookmark?resumed)
????????{
????????????text?=?(string)resumed.Payload;
????????????BookmarkManager?mgr?=?resumed.BookmarkManager;
????????????mgr.Remove(resumed);
????????????mgr.Done(false);
????????}
????}
????[Serializable]
????public?class?PrintKey?:?ProgramStatement
????{
????????private?string?key;
????????public?string?Key
????????{
????????????get?{?return?key;?}
????????}
????????public?override?void?Run(BookmarkManager?mgr)
????????{
????????????//?Print?the?key
????????????key?=?DateTime.Now.Millisecond.ToString();
????????????Console.WriteLine("here?is?your?key:?"?+?key);
????????????mgr.Done(false);
????????}
????}
????[Serializable]
????public?class?PrintGreeting?:?ProgramStatement
????{
????????private?string?key;
????????public?string?Key
????????{
????????????get?{?return?key;?}
????????????set?{?key?=?value;?}
????????}
????????private?string?s;
????????public?string?Input
????????{
????????????get?{?return?s;?}
????????????set?{?s?=?value;?}
????????}
????????public?override?void?Run(BookmarkManager?mgr)
????????{
????????????//沒有做特殊處理,key肯定是null.
????????????if?(string.IsNullOrEmpty(key))
????????????{
????????????????Console.WriteLine("OKOK");
????????????????return;
????????????}
????????????//?Print?the?greeting?if?the?key?is?provided
????????????if?(key.Equals(s))
????????????????Console.WriteLine("hello,?world");
????????????else
????????????{
????????????????Console.WriteLine("Wrong?key!");
????????????}
????????????mgr.Done(false);
????????}
????}
????[Serializable]
????public?class?ProgramStatementBlock?:?ProgramStatement
????{
????????int?currentIndex;
????????List<ProgramStatement>?statements?=?new?List<ProgramStatement>();
????????public?IList<ProgramStatement>?Statements
????????{
????????????get?{?return?statements;?}
????????}
????????public?override?void?Run(BookmarkManager?mgr)
????????{
????????????currentIndex?=?0;
????????????//?Empty?statement?block
????????????if?(statements.Count?==?0)
????????????????mgr.Done(true);
????????????else
????????????????mgr.RunProgramStatement(statements[0],?ContinueAt);
????????}
????????public?void?ContinueAt(Bookmark?resumed)
????????{
????????????BookmarkManager?mgr?=?resumed.BookmarkManager;
????????????//?If?we've?run?all?the?statements,?we're?done
????????????if?(++currentIndex?==?statements.Count)
????????????????mgr.Done(true);
????????????else?//?Else,?run?the?next?statement
????????????????mgr.RunProgramStatement(statements[currentIndex],?ContinueAt);
????????}
????}
????public?class?OpenSesame_v3
????{
????????static?void?Main(string[]?args)
????????{
????????????ProgramStatementBlock?openSesameProgram?=?new?ProgramStatementBlock();
????????????PrintKey?printKey?=?new?PrintKey();
????????????Read?read?=?new?Read();
????????????PrintGreeting?printGreeting?=?new?PrintGreeting();
????????????printGreeting.Key?=?printKey.Key;
????????????printGreeting.Input?=?read.Text;
????????????openSesameProgram.Statements.Add(printKey);
????????????openSesameProgram.Statements.Add(read);
????????????openSesameProgram.Statements.Add(printGreeting);
????????????MythicalRuntime?runtime?=?new?MythicalRuntime();
????????????ProgramHandle?handle?=?runtime.RunProgram(openSesameProgram);
????????????string?s?=?Console.ReadLine();
????????????//Bookmark的下半部分,用新的thread執行
????????????ThreadPool.QueueUserWorkItem(state?=>?runtime.Mgr.Resume("read",?state),?s);
????????????//?keep?the?main?thread?running
????????????Console.ReadLine();
????????}
????}
}
轉載于:https://www.cnblogs.com/cloudjun/archive/2009/04/04/1429299.html
總結
以上是生活随笔為你收集整理的WF本质论 OpenSesame 芝麻开门代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .h文件、.inc文件、.lib文件的功
- 下一篇: 《乐高EV3机器人搭建与编程》——2.1