混搭:多线程,协程,异步和等待

图片

前言


让我提醒您,此语言是我出于教育目的而开发的,是业余爱好的一部分。 我目前还不认为它是一种理想的开发语言,但是谁知道未来会怎样。

如果您希望自己尝试使用它-下载项目存储库 ,在其中可以找到适合您的OS的项目的组合版本或自己组合。

引言


在我们这个时代,多线程和异步是现代编程语言最重要的组成部分之一。

因此,我决定在我的编程语言中增加对现代设计和技术的支持,部分方法是向该语言添加简单方便的设计。

快速流动


它们使并行化代码执行变得容易。
为此,将启动:...最终构造添加到了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:根据您的评论,我从语言中删除了直到..end结构。 现在,它的位置由构造取代:

 whilst <>: ... end 

这是一个常规的while循环,不同之处在于在迭代之后检查条件。

Source: https://habr.com/ru/post/zh-CN442560/


All Articles