1. 程式人生 > >觀察者模式中多執行緒執行訂閱事件並順序執行的問題

觀察者模式中多執行緒執行訂閱事件並順序執行的問題

       對事件釋出訂閱模式中啟動執行緒執行操作,但又要保證執行緒順序執行的一些思考和實踐,在開發過程中,經常會遇到需要使用事件來觸發方法執行的情況,比如CS中按鈕的點選事件,滑鼠移動事件,鍵盤監聽事件等等,有時候需要執行比較耗時的任務,但並不希望阻塞主執行緒,導致介面卡頓,使用執行緒有不能保證執行緒像同步的執行順序一樣順序執行,因為有時候事件是系統觸發的所以沒有辦法等待,所以在這兒記錄下這個解決思路。

模擬情景:模擬事件訂閱的方法被多執行緒執行。

首先宣告一個TaskEventQueue類並使用單例模式,公開Regist方法,預設通過啟用執行緒的方式執行訂閱的方法,公開Invoke方法來發布事件。

通過下面的方式訂閱事件,現在遇到的問題是訂閱的方法不能按順序執行 ,

所以我考慮使用延續任務,來解決這一問題。

修改建構函式並新增一個Task屬性,延續任務必須是上一個任務處於正常執行完畢退出的狀態才能生效。

修改Regist方法通過重複指向的方式不斷疊加延續任務。

此時輸出的結果為:

普通的主執行緒執行結果為:

疑惑:是否有必要這麼做?

有時候會想,為什麼不直接在釋出事件時開一個執行緒執行呢?修改程式碼,試一下是可以的

答案是可以的,結果確實會順序執行,結果為:

但這是我們自己的程式碼可以隨意更改,如果是系統釋出的事件,就不是我們能干涉的了,不能要求系統也這麼做。

上述的方式其實只適用於業務場景併發量小的情況,在bs服務端暫時還沒有這樣的需求,但CS端可能會遇到。

注意:當前模擬場景中事件的釋出假設是無法更改的。

程式碼部分:

public class TaskEventQueue
    {
        TaskEventQueue()
        {
            ComplateTask = new Task(() => { });
            ComplateTask.Start();
        }

        volatile Task ComplateTask;

        public event Action SampleEvent;

        volatile static TaskEventQueue taskEventQueue;
 public static TaskEventQueue GetSingletionInstance()=>taskEventQueue??(taskEventQueue = new TaskEventQueue());

        public void Regist(Action action)
        {
            //SampleEvent += action;//主執行緒同步執行方式
            SampleEvent += () =>//採用多執行緒方式
            {
                if (action == null)
                {
                    throw new ArgumentException();
                }
                ComplateTask = ComplateTask.ContinueWith(t => action());
            };
        }

        public void Invok()
        {
            SampleEvent.Invoke();
        }
    }