C# 併發控制框架:單執行緒環境下實現每秒百萬級排程

小码编匠發表於2024-10-16

前言

在工業自動化和機器視覺領域,對實時性、可靠性和效率的要求越來越高。為了滿足這些需求,我們開發了一款專為工業自動化運動控制和機器視覺流程開發設計的 C# 併發流程控制框架。

該框架不僅適用於各種工業自動化場景,還能在單執行緒環境下實現每秒百萬次以上的排程頻率,從而從容應對涉及成千上萬輸入輸出點數的複雜任務。

併發流程控制框架

本框架提供一種全新的併發流程控制框架,它借鑑了Golang語言中的高效併發模式,並在此基礎上進行了必要的功能擴充套件。框架不僅能夠支援自定義的單/多執行緒排程機制,還允許在主UI執行緒中進行排程,從而簡化了邏輯與使用者介面之間的互動。

另外,該框架還整合了高精度定時器、可配置的排程優先順序、邏輯停止與暫停等功能,讓我們能夠更加靈活地管理和控制複雜的自動化流程。

框架優勢

  • 相較於傳統模型:相對於傳統的多執行緒模型、狀態機模型以及類PLC模型,本框架具有更加緊湊清晰的邏輯結構,顯著提升了開發效率,並簡化了後續的維護與升級過程。
  • 受Go語言啟發:框架的設計借鑑了 Go 語言中的高效併發模式,並在此基礎上進行了必要的功能擴充套件,以適應工業自動化領域的具體需求。
  • 靈活的排程機制:支援自定義單執行緒或多執行緒排程,同時也可在主 UI 執行緒中進行排程,便於邏輯與使用者介面的互動,增強了使用者體驗。
  • 豐富的內建功能:內建高精度定時器、可配置的排程優先順序、邏輯停止與邏輯暫停功能,確保任務執行的準確性和可控性。
  • 樹形多工排程:採用樹形結構管理多工排程,提高了邏輯的可靠性和系統的整體穩定性。
  • 卓越的效能表現:在單執行緒環境下,每秒可實現超過一百萬次的排程頻率,能夠從容應對成千上萬輸入輸出點數的複雜場景。
  • 廣泛的實踐驗證:該框架已在多個實際專案中成功應用,證明了其穩定性和可靠性。

框架示例

程式碼中定義了一系列不同的任務執行模式,展示如何透過不同的排程策略來管理併發任務。

  • 全域性變數

static shared_strand strand:全域性共享的排程器,用於保證執行緒安全。

  • 日誌記錄函式

Log(string msg):記錄帶有時間戳的日誌資訊到控制檯。

  • 工作任務函式

Worker(string name, int time = 1000):模擬一個簡單的任務,該任務會在指定的毫秒數後列印一條訊息。

  • 主函式

MainWorker():非同步主任務函式,依次呼叫前面定義的各種任務模式。

Main(string[] args):程式入口點,初始化工作服務、共享排程器,並啟動主任務。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Go;

namespace WorkerFlow
{
    class Program
    {
        static shared_strand strand;

        static void Log(string msg)
        {
            Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")} {msg}");
        }

        static async Task Worker(string name, int time = 1000)
        {
            await generator.sleep(time);
            Log(name);
        }

        //1 A、B、C依次序列
        //A->B->C
        static async Task Worker1()
        {
            await Worker("A");
            await Worker("B");
            await Worker("C");
        }

        //2 A、B、C全部並行,且依賴同一個strand(隱含引數,所有依賴同一個strand的任務都是執行緒安全的)
        //A
        //B
        //C
        static async Task Worker2()
        {
            generator.children children = new generator.children();
            children.go(() => Worker("A"));
            children.go(() => Worker("B"));
            children.go(() => Worker("C"));
            await children.wait_all();
        }

        //3 A執行完後,B、C再並行
        //  -->B
        //  |
        //A->
        //  |
        //  -->C
        static async Task Worker3()
        {
            await Worker("A");
            generator.children children = new generator.children();
            children.go(() => Worker("B"));
            children.go(() => Worker("C"));
            await children.wait_all();
        }

        //4 B、C都並行執行完後,再執行A
        //B--
        //  |
        //  -->A
        //  |
        //C--
        static async Task Worker4()
        {
            generator.children children = new generator.children();
            children.go(() => Worker("B"));
            children.go(() => Worker("C"));
            await children.wait_all();
            await Worker("A");
        }

        //5 B、C任意一個執行完後,再執行A
        //B--
        //  |
        //  >-->A
        //  |
        //C--
        static async Task Worker5()
        {
            generator.children children = new generator.children();
            var B = children.tgo(() => Worker("B", 1000));
            var C = children.tgo(() => Worker("C", 2000));
            var task = await children.wait_any();
            if (task == B)
            {
                Log("B成功");
            }
            else
            {
                Log("C成功");
            }
            await Worker("A");
        }

        //6 等待一個特定任務
        static async Task Worker6()
        {
            generator.children children = new generator.children();
            var A = children.tgo(() => Worker("A"));
            var B = children.tgo(() => Worker("B"));
            await children.wait(A);
        }

        //7 超時等待一個特定任務,然後中止所有任務
        static async Task Worker7()
        {
            generator.children children = new generator.children();
            var A = children.tgo(() => Worker("A", 1000));
            var B = children.tgo(() => Worker("B", 2000));
            if (await children.timed_wait(1500, A))
            {
                Log("成功");
            }
            else
            {
                Log("超時");
            }
            await children.stop();
        }

        //8 超時等待一組任務,然後中止所有任務
        static async Task Worker8()
        {
            generator.children children = new generator.children();
            children.go(() => Worker("A", 1000));
            children.go(() => Worker("B", 2000));
            var tasks = await children.timed_wait_all(1500);
            await children.stop();
            Log($"成功{tasks.Count}個");
        }

        //9 超時等待一組任務,然後中止所有任務,且在中止任務中就地善後處理
        static async Task Worker9()
        {
            generator.children children = new generator.children();
            children.go(() => Worker("A", 1000));
            children.go(async delegate ()
            {
                try
                {
                    await Worker("B", 2000);
                }
                catch (generator.stop_exception)
                {
                    Log("B被中止");
                    await generator.sleep(500);
                    throw;
                }
                catch (System.Exception)
                {
                }
            });
            var task = await children.timed_wait_all(1500);
            await children.stop();
            Log($"成功{task.Count}個");
        }

        //10 巢狀任務
        static async Task Worker10()
        {
            generator.children children = new generator.children();
            children.go(async delegate ()
            {
                generator.children children1 = new generator.children();
                children1.go(() => Worker("A"));
                children1.go(() => Worker("B"));
                await children1.wait_all();
            });
            children.go(async delegate ()
            {
                generator.children children1 = new generator.children();
                children1.go(() => Worker("C"));
                children1.go(() => Worker("D"));
                await children1.wait_all();
            });
            await children.wait_all();
        }

        //11 巢狀中止
        static async Task Worker11()
        {
            generator.children children = new generator.children();
            children.go(() => Worker("A", 1000));
            children.go(async delegate ()
            {
                try
                {
                    generator.children children1 = new generator.children();
                    children1.go(async delegate ()
                    {
                        try
                        {
                            await Worker("B", 2000);
                        }
                        catch (generator.stop_exception)
                        {
                            Log("B被中止1");
                            await generator.sleep(500);
                            throw;
                        }
                        catch (System.Exception)
                        {
                        }
                    });
                    await children1.wait_all();
                }
                catch (generator.stop_exception)
                {
                    Log("B被中止2");
                    throw;
                }
                catch (System.Exception)
                {
                }
            });
            await generator.sleep(1500);
            await children.stop();
        }

        //12 並行執行且等待一組耗時演算法
        static async Task Worker12()
        {
            wait_group wg = new wait_group();
            for (int i = 0; i < 2; i++)
            {
                wg.add();
                int idx = i;
                var _ = Task.Run(delegate ()
                {
                    try
                    {
                        Log($"執行演算法{idx}");
                    }
                    finally
                    {
                        wg.done();
                    }
                });
            }
            await wg.wait();
            Log("執行演算法完成");
        }

        //13 序列執行耗時演算法,耗時演算法必需放線上程池中執行,否則依賴同一個strand的排程將不能及時
        static async Task Worker13()
        {
            for (int i = 0; i < 2; i++)
            {
                await generator.send_task(() => Log($"執行演算法{i}"));
            }
        }

        static async Task MainWorker()
        {
            await Worker1();
            await Worker2();
            await Worker3();
            await Worker4();
            await Worker5();
            await Worker6();
            await Worker7();
            await Worker8();
            await Worker9();
            await Worker10();
            await Worker11();
            await Worker12();
            await Worker13();
        }

        static void Main(string[] args)
        {
            work_service work = new work_service();
            strand = new work_strand(work);
            generator.go(strand, MainWorker);
            work.run();
            Console.ReadKey();
        }
    }
}

框架地址

  • Gitee: https://gitee.com/hamasm/CsGo

總結

值得一提的是,該框架特別設計用於工業自動化運動控制以及機器視覺流程開發領域,其獨特的樹形多工排程機制極大提高了邏輯的可靠性,同時單執行緒環境下的每秒排程次數可達一百萬次以上,足以應對涉及成千上萬輸入輸出點數的應用場景。經過多個專案的實際驗證,證明了其穩定性和可靠性,為工業自動化提供了強有力的支援。

透過本文的介紹,希望能為工業自動化領域的開發者提供一個高效、可靠且易於使用的工具。藉助這一工具,大家在構建複雜的控制系統時,能夠更加輕鬆地應對併發處理的挑戰。也期待您在評論區留言交流,分享您的寶貴經驗和建議。

最後

如果你覺得這篇文章對你有幫助,不妨點個贊支援一下!你的支援是我繼續分享知識的動力。如果有任何疑問或需要進一步的幫助,歡迎隨時留言。

也可以加入微信公眾號[DotNet技術匠] 社群,與其他熱愛技術的同行一起交流心得,共同成長!優秀是一種習慣,歡迎大家留言學習!

相關文章