マッシュ:マルチスレッド、コルーチン、非同期&待機

画像



まえがき



この言語は、趣味の一環として教育目的で開発されたことを思い出させてください。 私はそれを(現時点では)理想的に開発された言語とは考えていませんが、誰が未来に期待できるかを知っています。



自分で実際に試してみたい場合はプロジェクトリポジトリをダウンロードしますプロジェクトリポジトリでは、OS用にプロジェクトのアセンブルバージョンを見つけるか、自分でアセンブルできます。



はじめに



現在のマルチスレッドと非同期は、現代のプログラミング言語の最も重要なコンポーネントの1つです。



そのため、一部にはシンプルで便利なデザインを言語に追加することにより、プログラミング言語に最新のデザインとテクノロジーのサポートを追加することにしました。



速い流れ



コードの実行を簡単に並列化できます。

これを行うために、launch:... endコンストラクトがMashに追加されました



コード例:



uses <bf> uses <crt> proc main(): for(i ?= 1; i <= 10; i++): launch: sleep(random() * 100) println(i) end end inputln() end
      
      





出力例:



 9 1 2 7 5 3 10 4 6 8
      
      





プログラムの実行がlaunch..endに達すると、このブロック内のコードが別のスレッドで起動され、起動コードの実行がこのブロックに転送されます。



Kotlinプログラミング言語の初期段階で、ほぼ同じ言語構成要素に出会うことができました。



非同期と待機



コルーチンの実装だけでは十分ではありません。そのため、非同期&待機構造もMashに追加されます。



非同期では、コードの実行を別のスレッドに変換し、メインコードの実行を継続できます。



待機により、必要なすべての非同期ブロックが実行される瞬間を待つことができます。



コード例:



 uses <bf> uses <crt> proc main(): println("Hello!") async a: println("Test") sleep(1000) println("Test") sleep(1000) println("Test") sleep(1000) end async b: println("Test 2") sleep(300) println("Test 2") sleep(300) println("Test 2") sleep(300) end wait a, b println("End!") inputln() end
      
      





結論:



 Hello! Test Test 2 Test 2 Test 2 Test Test End!
      
      





クラシックマルチスレッド



マルチスレッドのサポートを提供するメインコードベースは、モジュール<threads>に集中しています。



後で説明する主なコンポーネント:



1)TThreadクラス(クラス宣言のみが与えられ、完全なコードはモジュール内にさらにあります):



 class TThread: protected: var ThreadContext public: var Resumed, Terminated, FreeOnTerminate proc Create, Free proc Execute //for overriding proc Suspend, Resume, Terminate, WaitFor, ReJoin //Control proc's end
      
      





2)TCriticalSectionクラス(その説明):



 class TCriticalSection: protected: var Critical_Section_Controller public: proc Create, Free //Methods proc Enter, Leave func TryEnter end
      
      







3)スレッドを迅速に作成および開始する方法:

 func Async(method, ...) func Thread(method, ...) func Parallel(method, ...)
      
      







4)スレッドセーフアトミック(スレッド間相互作用の変数クラス):

 class TAtomic: private: var Locker, Value public: proc Create, Free proc Set func Get end
      
      







5)コルーチン:

 class TCoroutine(TThread): public: var NextCoroutine proc Create proc Yield, YieldFor end
      
      







それで、順番に取りましょう。



TThreadクラスを使用すると、それに基づいて新しい後続クラスを作成し、必要な変数をそのフィールドに追加して、新しいスレッドに転送できます。



すぐにサンプルコード:



 uses <bf> uses <crt> uses <threads> class MyThreadClass(TThread): var Param proc Create, Execute end proc MyThreadClass::Create(Param): $Param ?= Param TThread::Create$(true) end proc MyThreadClass::Execute(): for(i ?= 0; i < 10; i++): PrintLn(i, ": ", $Param) end end proc main(): new MyThreadClass("Thread #2!") InputLn() end
      
      





ストリームを作成するために新しいクラスを記述するのが面倒な場合は、クラスインスタンスのメソッドの動的再定義のサポートを思い出して使用できます。



コード例:



 uses <bf> uses <crt> uses <threads> proc class::MyThreadedProc(): for(i ?= 0; i < 10; i++): PrintLn(i, ": Threaded hello!") end end proc main(): Thr ?= new TThread(false) Thr->Execute ?= class::MyThreadedProc Thr->Resume() InputLn() end
      
      





新しいスレッドでパラメーターを指定してメソッドを実行するだけでよい場合は、async()、thread()、parallel()メソッドが必要です。



新しいスレッドでメソッドを開始する例:



 uses <bf> uses <crt> uses <threads> proc ThreadedProc(Arg): for(i ?= 0; i < 10; i++): PrintLn(i, ": ", Arg) end end proc main(): Async(ThreadedProc, "Thread #1!") InputLn() end
      
      





先ほどお気づきかもしれませんが、これら3つのメソッドは関数であり、TThreadに似たクラスを返します。



違いは、async()がスレッドを作成し、完了時にメモリをそれ自体から解放し、TThreadクラスのインスタンスが自動的に削除されることです。

thread()はasync()と同じで、スレッドのみが最初にフリーズされて作成されます。

そして最後にparallel()-実行中のスレッドを作成します。完了時に自己破壊を実行しません。 TThreadクラスのメソッド(WaitFor()など)を使用でき、実行時エラーを恐れることはありません。 唯一の注意点-Free()を手動で呼び出す必要があります。



スレッド同期



これを行うために、TCriticalSectionクラスをMashに追加しました。



コード例:



 uses <bf> uses <crt> uses <threads> var CSect = new TCriticalSection() proc ThreadedProc(Arg): while true: CSect -> Enter() PrintLn(Arg) CSect -> Leave() Sleep(10) gc() end end proc CriticalThreadedProc(): while true: Sleep(3000) CSect -> Enter() Sleep(1000) PrintLn("And now...") Sleep(1000) PrintLn("Time to...") Sleep(1000) PrintLn("Critical section!") Sleep(3000) CSect -> Leave() gc() end end proc main(): Async(ThreadedProc, "I'm thread #1!!!") Async(CriticalThreadedProc) InputLn() end
      
      







アトミック



任意の値を保存するためのスレッドセーフコンテナの実装。



コード例:

 uses <bf> uses <crt> uses <threads> proc main(): MyThreadValue ?= new TAtomic(0) launch: while true: MyThreadValue -> Set(1) Sleep(8) gc() end end launch: while true: MyThreadValue -> Set(2) Sleep(3) gc() end end launch: while true: MyThreadValue -> Set(3) Sleep(11) gc() end end while true: PrintLn(MyThreadValue -> Get()) Sleep(100) gc() end end
      
      







コルーチン



この機能により、コードの並列実行を同期できます。



コード例:

 uses <bf> uses <crt> uses <threads> proc class::Proc1(): while true: println("Hello world #1") sleep(100) gc() $yield() end end proc class::Proc2(): while true: println("Hello world #2") sleep(100) gc() $yield() end end proc class::Proc3(): while true: println("Hello world #3") sleep(100) gc() $yield() end end proc main(): cor3 ?= new TCoroutine(false, null) cor3 -> Execute ?= class::Proc3 cor2 ?= new TCoroutine(false, cor3) cor2 -> Execute ?= class::Proc2 cor1 ?= new TCoroutine(false, cor2) cor1 -> Execute ?= class::Proc1 cor3 -> NextCoroutine ?= cor1 cor1 -> Resume() InputLn() end
      
      







結論:

 Hello world #1 Hello world #2 Hello world #3 Hello world #1 Hello world #2 Hello world #3 ...
      
      







おわりに



この記事がおもしろいと思います。



コメントを待っています:)



PS:あなたのコメントによると、until..end構文を言語から削除しました。 今、その場所は建設によって取られています:



 whilst <>: ... end
      
      





通常のwhileループですが、反復後に条件がチェックされるという違いがあります。



All Articles