你程式會做飯嘛?我能!
別嘲笑這個標題。我想了很久。有點“投機取巧”的功效吧!
程式當然不能做飯。
之前的我們的系列文章,介紹, 多執行緒執行,任務派發。定時器執行。指令碼載入。程式狀態機。
這些都是零零散散,或者說都是模組化介紹,以及模組測試用例。
那麼今天我們就來模擬正常程式流程。使用上述的功能性程式碼完成流程。
當然今天的測試用例程式肯定和做飯有關。今天要做的是模擬一個餐廳的流程。
完成 客人入座 -> 點菜 -> 等待就餐 -> 就餐 -> 等待結賬 -> 結賬 -> 離開.
期間包括 等待就餐 新增茶水,就餐的新增茶水,新增米飯等隨機事件
新建控制檯專案:
Sz.Network.DiningRoom 用於存放主檔案專案
類庫
Sz.Network.DiningRoom.Scripts 用於存放指令碼檔案專案
我們先來初始化餐廳。
/** * * @author 失足程式設計師 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 * */ namespace Sz.Network.DiningRoom { /// <summary> /// /// </summary>public class 餐廳 { private static 餐廳 instance = new 餐廳(); public static 餐廳 GetInstance { get { return instance; } } public long 全域性執行緒 = 0; public long 廚師s = 0; public long 傳菜員s = 0; public long 服務員s = 0; public long 配菜員s = 0;public long 收銀員s = 0; public long 洗菜員s = 0; public 客人[] table = null; public void Init(int tableSize) { Logger.Info("初始化餐廳"); //所有的工作人員都是一個執行緒 全域性執行緒 = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("全域性執行緒", 1)); //所有的工作人員都是一個執行緒 廚師s = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("廚師", 3)); //所有的工作人員都是一個執行緒 傳菜員s = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("傳菜員", 5)); //所有的工作人員都是一個執行緒 服務員s = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("服務員", 5)); //所有的工作人員都是一個執行緒 配菜員s = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("配菜員", 3)); //所有的工作人員都是一個執行緒 收銀員s = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("收銀員", 1)); //所有的工作人員都是一個執行緒 洗菜員s = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("洗菜員", 2)); table = new 客人[tableSize]; for (int i = 0; i < tableSize; i++) { Logger.Info("初始化餐桌 " + (i + 1) + " 號桌"); } } } }
每一個工作人員都是一個執行緒。模擬執行緒。
我們這裡,餐廳配置:"廚師", 3 "傳菜員", 5 "服務員", 5 "配菜員", 3 "收銀員", 1 "洗菜員", 2
各個環節的人員都不相同,且每一步操作都不進相同。
接下來我們初始化客人,
/** * * @author 失足程式設計師 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 * */ namespace Sz.Network.DiningRoom { public class 客人 { public static EnumStatus Status入座 = new EnumStatus(1 << 0, 0x000000); public static EnumStatus Status取消 = new EnumStatus(1 << 1, 0x000000); public static EnumStatus Status點菜 = new EnumStatus(1 << 2, 0x000000); public static EnumStatus Status就餐 = new EnumStatus(1 << 3, 0x000000); public static EnumStatus Status結賬中 = new EnumStatus(1 << 4, 0x000000); public static EnumStatus Status等待就餐 = new EnumStatus(1 << 5, 0x000000); public static EnumStatus Status等待結賬 = new EnumStatus(1 << 6, 0x000000); /// <summary> /// 儲存臨時資料的 /// </summary> public ObjectAttribute TempAttribute = new ObjectAttribute(); /// <summary> /// 客人當前的狀態 /// </summary> public EnumStatus Staus = new EnumStatus(0, 0x000000); public List<菜餚> 菜餚s = new List<菜餚>(); public int TableID { get; set; } /// <summary> /// 每一個客人的隨機標識 /// </summary> public string guidID { get; set; } public 客人(int tableID) { guidID = Guid.NewGuid().ToString().Replace("-", ""); this.TableID = tableID; Staus |= Status入座; Show(); } public void 點菜() { ThreadPool.ThreadManager.GetInstance.AddTask(餐廳.GetInstance.服務員s, new Task點菜(this)); Task隨機事件發生處理器 task = new Task隨機事件發生處理器(this.TableID + " 號桌客人 上碗筷"); ThreadPool.ThreadManager.GetInstance.AddTask(餐廳.GetInstance.服務員s, task); } public void Add點菜(菜餚 菜) { 菜餚s.Add(菜); ThreadPool.ThreadManager.GetInstance.AddTask(餐廳.GetInstance.洗菜員s, new Task菜(this, 菜)); } public void Show() { string 狀態 = ""; if (Staus.HasFlag(Status入座)) { 狀態 = "入座"; } else if (Staus.HasFlag(Status取消)) { 狀態 = "取消"; } else if (Staus.HasFlag(Status點菜)) { 狀態 = "點菜"; } else if (Staus.HasFlag(Status等待就餐)) { 狀態 = "等待就餐"; } else if (Staus.HasFlag(Status就餐)) { 狀態 = "就餐"; } else if (Staus.HasFlag(Status等待結賬)) { 狀態 = "等待結賬"; } else if (Staus.HasFlag(Status結賬中)) { 狀態 = "結賬中"; } Logger.Info(this.TableID + " 號桌子 客人 " + this.guidID + " 當前狀態:" + 狀態); } } }
初始化菜餚
/** * * @author 失足程式設計師 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 * */ namespace Sz.Network.DiningRoom { public class 菜餚 { public static EnumStatus Status點菜 = new EnumStatus(1 << 0, 0x000000); public static EnumStatus Status取消 = new EnumStatus(1 << 1, 0x000000); public static EnumStatus Status洗菜 = new EnumStatus(1 << 2, 0x000000); public static EnumStatus Status配菜 = new EnumStatus(1 << 3, 0x000000); public static EnumStatus Status炒菜 = new EnumStatus(1 << 4, 0x000000); public static EnumStatus Status傳菜 = new EnumStatus(1 << 5, 0x000000); public static EnumStatus Status就餐 = new EnumStatus(1 << 6, 0x000000); public static EnumStatus Status結束就餐 = new EnumStatus(1 << 7, 0x000000); public string Name { get; private set; } public EnumStatus Staus = new EnumStatus(0, 0x000000); /// <summary> /// 儲存臨時資料的 /// </summary> public ObjectAttribute TempAttribute = new ObjectAttribute(); public 菜餚(string name) { this.Name = name; Staus |= Status點菜; Show(); } public void Show() { string 狀態 = ""; if (Staus.HasFlag(Status點菜)) { 狀態 = "點菜"; } else if (Staus.HasFlag(Status取消)) { 狀態 = "取消"; } else if (Staus.HasFlag(Status洗菜)) { 狀態 = "洗菜"; } else if (Staus.HasFlag(Status配菜)) { 狀態 = "配菜"; } else if (Staus.HasFlag(Status炒菜)) { 狀態 = "炒菜"; } else if (Staus.HasFlag(Status傳菜)) { 狀態 = "傳菜"; } else if (Staus.HasFlag(Status就餐)) { 狀態 = "就餐"; } Logger.Info(this.Name + " 當前狀態:" + 狀態); } } }
我們需要建立一個定時器任務,對餐桌和客人進行狀態監測和隨機事件發生器
/** * * @author 失足程式設計師 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 * */ namespace Sz.Network.DiningRoom { public class TimerTask : ThreadPool.TimerTask { /// <summary> /// 間隔 5000 毫秒執行一次 /// </summary> public TimerTask() : base(餐廳.GetInstance.全域性執行緒, 2000) { } public override void Run() { IEnumerable<IScript餐桌檢查器> checkScripts = LoadScriptPool.LoadScriptManager.GetInstance.GetInstances<IScript餐桌檢查器>(); foreach (var item in checkScripts) { item.Run(); } } } }
由於我們餐桌檢查器是一個不定數,所以需要放到指令碼去。方便更新程式程式碼。
在指令碼專案裡面建立指令碼檔案
/** * * @author 失足程式設計師 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 * */ namespace Sz.Network.DiningRoom.Scripts { public class Script餐桌檢查器 : IScript餐桌檢查器 { Random random = new Random(DateTime.Now.Millisecond); public Script餐桌檢查器() { } public void Run() { Logger.Info("==================================Script餐桌檢查器======================================="); for (int i = 0; i < 餐廳.GetInstance.table.Length; i++) { if (餐廳.GetInstance.table[i] == null) { int randomValue = random.Next(10000); if (randomValue < 5000) { 客人 客 = new 客人(i + 1); 餐廳.GetInstance.table[i] = 客; } } else { 客人 客 = 餐廳.GetInstance.table[i]; if (客.Staus.HasFlag(客人.Status入座)) { ///如果客人剛剛入座,執行點菜,移交給服務員 客.Staus |= 客人.Status點菜; 客.點菜(); } else if (客.Staus.HasFlag(客人.Status等待就餐)) { bool isFor = true; foreach (var item in 客.菜餚s) { if (!item.Staus.HasFlag(菜餚.Status就餐)) { isFor = false; break; } } if (isFor) { 客.Staus |= 客人.Status就餐; //模擬客人吃飯需要30到50秒 客.TempAttribute["Status就餐"] = SzExtensions.CurrentTimeMillis() + (random.Next(3, 6)) * 10 * 1000; } else { //模擬隨機事件 int randomValue = random.Next(10000); if (randomValue < 6000) { Logger.Info("隨機事件發生 " + (i + 1) + " 號桌客人 新增茶水"); Task隨機事件發生處理器 task = new Task隨機事件發生處理器((i + 1) + " 號桌客人 新增茶水"); ThreadPool.ThreadManager.GetInstance.AddTask(餐廳.GetInstance.服務員s, task); } } } else if (客.Staus.HasFlag(客人.Status就餐)) { if (客.TempAttribute.GetlongValue("Status就餐") < SzExtensions.CurrentTimeMillis()) { 客.Staus |= 客人.Status等待結賬; } else { //模擬隨機事件 string msg = ""; int randomValue = random.Next(10000); if (randomValue < 3000) { msg = " 新增米飯"; } else if (randomValue < 6000) { msg = " 新增茶水"; } if (!string.IsNullOrWhiteSpace(msg)) { Logger.Info("隨機事件發生 " + (i + 1) + " 號桌客人 " + msg); Task隨機事件發生處理器 task = new Task隨機事件發生處理器((i + 1) + " 號桌客人 " + msg); ThreadPool.ThreadManager.GetInstance.AddTask(餐廳.GetInstance.服務員s, task); } } } else if (客.Staus.HasFlag(客人.Status等待結賬)) { 客.Staus |= 客人.Status結賬中; } else if (客.Staus.HasFlag(客人.Status結賬中)) { Logger.Info((i + 1) + " 號桌客人 結束就餐 送走客人"); 餐廳.GetInstance.table[i] = null; return; } 客.Show(); } } } } }
點菜也同樣為方便程式更新,程式碼放在指令碼執行
/** * * @author 失足程式設計師 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 * */ namespace Sz.Network.DiningRoom.Scripts { public class Script點菜 : IScript點菜 { public Script點菜() { } public void Run(客人 客) { List<string> 菜餚_葷菜s = new List<string>() { "回鍋肉", "青椒肉絲", "東坡肘子", "糖醋排骨", "魚香肉絲" }; List<string> 菜餚_素菜s = new List<string>() { "空心菜", "鳳尾", "素炒竹筍", "白油絲瓜" }; List<string> 菜餚_湯s = new List<string>() { "番茄煎蛋湯", "紫菜蛋花湯", "酸菜粉絲湯", "素菜湯", "肉片湯" }; Random random = new Random(DateTime.Now.Millisecond); { //int 數量 = random.Next(1, 菜餚_葷菜s.Count); int 數量 = 1; for (int i = 0; i < 數量; i++) { int index = random.Next(菜餚_葷菜s.Count); string name = 菜餚_葷菜s[index]; 菜餚_葷菜s.RemoveAt(index); 菜餚 菜 = new 菜餚(name); 客.Add點菜(菜); } } { //int 數量 = random.Next(1, 菜餚_素菜s.Count); int 數量 = 1; for (int i = 0; i < 數量; i++) { int index = random.Next(菜餚_素菜s.Count); string name = 菜餚_素菜s[index]; 菜餚_素菜s.RemoveAt(index); 菜餚 菜 = new 菜餚(name); 客.Add點菜(菜); } } { //int 數量 = random.Next(1, 菜餚_湯s.Count); int 數量 = 1; for (int i = 0; i < 數量; i++) { int index = random.Next(菜餚_湯s.Count); string name = 菜餚_湯s[index]; 菜餚_湯s.RemoveAt(index); 菜餚 菜 = new 菜餚(name); 客.Add點菜(菜); } } 客.Staus |= 客人.Status等待就餐; } } }
接下來,就是菜的流程任務執行器
/** * * @author 失足程式設計師 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 * */ namespace Sz.Network.DiningRoom { public class Task菜 : ThreadPool.TaskModel { public 客人 客 { get; set; } public 菜餚 _菜餚 { get; set; } public Task菜(客人 客, 菜餚 _菜餚) { this.客 = 客; this._菜餚 = _菜餚; } public override void Run() { Random random = new Random(DateTime.Now.Millisecond); string 事件 = ""; EnumStatus tempStatus = null; long threadID = 0; if (_菜餚.Staus.HasFlag(菜餚.Status點菜)) { 事件 = "洗菜"; tempStatus = 菜餚.Status洗菜; threadID = 餐廳.GetInstance.洗菜員s; } else if (_菜餚.Staus.HasFlag(菜餚.Status取消)) { 事件 = "取消"; tempStatus = 菜餚.Status取消; } else if (_菜餚.Staus.HasFlag(菜餚.Status洗菜)) { 事件 = "配菜"; tempStatus = 菜餚.Status配菜; threadID = 餐廳.GetInstance.配菜員s; } else if (_菜餚.Staus.HasFlag(菜餚.Status配菜)) { 事件 = "炒菜"; tempStatus = 菜餚.Status炒菜; threadID = 餐廳.GetInstance.廚師s; } else if (_菜餚.Staus.HasFlag(菜餚.Status炒菜)) { 事件 = "傳菜"; tempStatus = 菜餚.Status傳菜; threadID = 餐廳.GetInstance.傳菜員s; } else { return; } int timer = random.Next(2000, 5000); ///模擬耗時 Thread.Sleep(timer); ///修改菜餚的狀態 this._菜餚.Staus |= tempStatus; Logger.Info(Thread.CurrentThread.Name + " " + 客.TableID + " 號桌 客人 " + this._菜餚.Name +" "+ 事件 + " 耗時:" + timer); if (this._菜餚.Staus.HasFlag(菜餚.Status傳菜)) { ///修改菜餚的狀態 this._菜餚.Staus |= 菜餚.Status就餐; } if (threadID > 0) { //移交到下一個工作人員(執行緒) ThreadPool.ThreadManager.GetInstance.AddTask(threadID, this); } } } }
我們修改一下餐廳的 init 方法
//載入指令碼 LoadScriptPool.LoadScriptManager.GetInstance.LoadCSharpFile(new string[] { @"..\..\..\Sz.Network.DiningRoom.Scripts\" }); //初始化定時器任務 ThreadPool.ThreadManager.GetInstance.AddTimerTask(new TimerTask());
菜餚的流程,交給了 Task菜 類處理,菜餚的狀態值修改也是要交給 Task菜 修改的,保證了在同一執行緒修改狀態值就保證狀態值的正常。
既然說了要有隨機事件發生,那肯定少不了隨機事件的處理器
/** * * @author 失足程式設計師 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 * */ namespace Sz.Network.DiningRoom { public class Task隨機事件發生處理器 : ThreadPool.TaskModel { string msg; public Task隨機事件發生處理器(string msg) { this.msg = msg; } public override void Run() { Random random = new Random(DateTime.Now.Millisecond); int timer = random.Next(2000, 5000); //模擬隨機事件耗時 Thread.Sleep(timer); Logger.Info(Thread.CurrentThread.Name + " 處理隨機事件發生 " + msg + " 耗時:" + timer); } } }
這樣我們就能啟動程式了測試一下了。
整個流程就是,客人入座,點菜,,被分配到到洗菜,配菜,炒菜,傳菜。就餐。結賬。等一系列流程。
由於人員配置不同,具體工作耗時不同,所以一切都發生都是不定項;
每一個操作在移交給下一個工作者(執行緒)都是不定操作。而每一個工作者(執行緒)都有先來後到的原則進行自己工作的處理;
我們未來方便測試和看清楚執行流程。我們只開啟一個餐桌;
餐廳.GetInstance.Init(1);
我的程式真的能做飯哦~!
不知道,這樣講,是否能幫你講明白呢???
老規矩,全套原始碼奉獻 svn 地址 http://code.taobao.org/svn/flynetwork_csharp/trunk/Flynetwork/BlogTest
跪求保留
/** * * @author 失足程式設計師 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 * */