1. 程式人生 > 其它 >搶佔式協程排程新語言

搶佔式協程排程新語言

技術標籤:開發語言指令碼指令碼語言程式語言luac語言

轉載自本人今日頭條:https://www.toutiao.com/i6915650155899453966/
轉載請註明出處

協程這個概念想必大家現在已經不會太過陌生了,畢竟不管是LUA還是GO抑或Kotlin甚至C++都有了協程。

雖然協程已經廣泛出現了,但是各家的實現還是有所不同的。例如LUA,它的協程屬於主動讓出式的排程方式,即如果不主動讓出執行許可權,當前協程會一直執行而不會讓其他協程執行。而有些語言的協程還是可以跨執行緒的執行的,可以說是實現方式五花八門。

今天給大家介紹的一款新語言就是一款按時間片搶佔式排程的協程指令碼語言,即每一個協程不需要顯示呼叫某些特定函式來讓出控制權,而是按照執行時間的權重來控制是否掛起還是執行。

這就是我們今天的主題——Melang (官方站點 https://melang.org/)
在這裡插入圖片描述

搶佔式協程排程新語言
我們將討論如下幾方面內容:

  • 語言特性
  • 社群特性
  • 使用場景
  • 語言特性

語言特性

對於一款語言,它都註定會有迴圈、判斷、陣列、結構等等必要組成部分,這些Melang與其他語言並無二致,讀者可以在Melang的官方站點找到相關文件。所以我們的重點就放在了以下方面上:

1.協程搶佔式排程

這是這個語言最大的特點。在Melang中,每一個指令碼任務都是一個獨立的協程,協程與協程間是環境隔離的,如果需要通訊,則需要使用訊息函式進行通訊。

我們看兩個例子:

利用melang可執行程式啟動多個指令碼任務

假設我有如下兩個指令碼檔案:

//a.mln
while (true) {
  @mln_print('a');
}
//b.mln
while (true) {
  @mln_print('b');
}

我執行如下命令:

# melang a.mln b.mln

執行後,會看到螢幕交替列印a和b,如下:

...
b
b
b
a
a
a
a
a
...

且使用top命令會發現只有一個程序(同時也只有一個執行緒)在執行這兩個任務。

melang的排程並非發生在函式mln_print中,而是在處理每條語句的過程中都會嘗試切換

在melang任務中拉起多個指令碼任務

我們保留上一例子中的兩個程式碼檔案,並增加如下程式碼檔案:

//launcher.mln
@mln_eval('a.mln');
@mln_eval('b.mln');

然後執行:

# melang launcher.mln

我們將會看到和上一例相同的輸出結果,只是這一次,a和b兩個任務是由另一個指令碼任務通過函式mln_eval拉起的。

2.反射

反射用網友的一句話來總結就是:

在執行時才知道要操作的類是什麼,並且可以在執行時獲取類的完整構造,並呼叫對應的方法。

在Melang中,類的概念稱作集合(Set),不過更類似於C中的結構體,但還支援函式定義。

我們看一個簡單的例子:

Human {
  name;
  age;
  @init (name, age) {
    this.name = name;
    this.age = age;
  }
}

這裡我們定義了一個名為Human的集合結構,它有兩個成員變數——name和age,以及一個方法——init。

常規例項化程式碼如下:

me = $Human;

這樣就例項化了一個Human物件,名為me。

然而我們也可以如此例項化:

str = 'Human';
me = $str;

這個效果是一樣的。

然後我們就可以呼叫物件的方法了:

me.init('Tom', 18);

在Melang中,不僅集合結構可以通過字串來獲取,函式以及物件方法都可以如此使用。

函式的例子

@foo ()
{
  @mln_print('foo');
}
a = 'foo';
a();

這裡我們定義了一個函式,但是我們並不直接呼叫它,而是通過一個字串型別變數來間接呼叫。

物件方法的例子

Human {
  name;
  age;
  action;
  @init (name, age) {
    this.name = name;
    this.age = age;
  }
}

me = $Human;
me.action = 'init';
me.action('Tom', 18);
@mln_print(me.name);

可以看到,本例中,我們通過成員變數中的字串來呼叫物件的方法。

3.注入

對於一個已經例項化的物件,我們依舊可以對其成員和方法進行增加(或者說注入),例如:

Human {
}
someone = $Human;
someone.age = 20;
@mln_print(someone.age);

這段程式碼會輸出20。說明age成員被成功加入someone物件。

注意:注入是針對物件的,而不是集合結構定義的。因此如果再對Human進行例項化,依舊沒有age成員的。

上面這個例子是一種最簡單的注入,Melang還提供了類似其他指令碼的set和get函式。

我們再來看一個注入方法的例子:

Human {
  age;
}
@printAge()
{
  @mln_print(this.age);
}
someone = $Human;
someone.age = 20;
someone.print = printAge;
someone.print();

這個例子依舊會輸出20,只是這次是由注入的方法呼叫mln_print進行輸出的。

4.響應式程式設計

這一特性是借鑑於一些web前端開發的內容,是利用一組函式對變數進行監控,當值發生改變時,會呼叫設定好的回撥函式進行處理。(注意,即便新賦予的值與舊值相同也會被呼叫)

示例:

@eventHandler(newdata, userData)
{
  @mln_print(newdata);
  @mln_print(userData);
}
n = 0;
@mln_watch(n, eventHandler, 'this is an useData');
for (; n < 5; ++n)
  ;

這裡,利用mln_watch函式對變數n進行跟蹤,當n的值改變時,就會觸發eventHandler函式進行呼叫。我們將看到如下輸出:

1
this is an useData
2
this is an useData
3
this is an useData
4
this is an useData
5
this is an useData

5.同步程式碼非同步執行

Melang的程式碼在寫法上都是同步的形式。同步形式的好處就是邏輯連貫,不會像非同步處理那樣邏輯跳來跳去。在傳統語言中,同步寫法也意味著同步處理,因此效能是較低的。但在Melang中,底層直譯器是純非同步執行的。

舉個簡單的例子:

//a.mln
while (true) {
  @mln_msgQueueSend('queue', 'a');
  ret = @mln_msgQueueRecv('queue');
  @mln_print(ret);
}
//b.mln
while (true) {
  ret = @mln_msgQueueRecv('queue');
  @mln_print(ret);
  @mln_msgQueueSend('queue', 'b');
}

這兩個指令碼任務的是利用訊息佇列函式互發訊息互收對方訊息並打印出來。對於每一個任務而言,它的邏輯都是同步的順序的,例如a.mln就是一定是先發訊息,然後收訊息,然後列印。只是a在接收時,如果b並未給a發訊息,則a會掛起等待。

當然,上面的例子只是一個簡單的例子,涉及到網路IO的情況也是一樣的。當套接字上有資料到達時,直譯器會接收,然後返回給上層指令碼,並將該指令碼從掛起態改為執行態。

社群特性

Melang的核心庫程式碼雖然已經有幾年的積累,但社群還處於萌芽階段。現今業界絕大多數開源專案都是依託某些名企崛起的,但也有一些知名專案是有個人推動發展起來的。

在這先簡單討論下這兩者的利弊:

依託企業,優點自然就是推廣相對容易,由企業做背書,使用者相對放心。但缺點是容易造成版權糾紛而吃官司(參見網路上安卓使用java侵權甲骨文的相關文章),也就導致了專案的發展無法完全由社群推動,而是由公司主導。

依託個人,優點就是規避了公司層面的侵權問題,可以極大地利用社群優勢對專案進行擴張更新。缺點就是,前期推廣很難,因為缺少名企背書,導致使用者使用時依舊心懷疑慮擔心穩定性安全性等問題。但是,這類專案也不乏成功先例,例如Vue。

目前Melang專案仍是個人運作,未來也是期望能夠發展為社群主導。

使用場景

目前Melang的使用場景主要還是嵌入其他應用,這與LUA基本相同。Melang在Github上的專案就是一個啟動器,啟動器會呼叫核心庫中指令碼相關函式進行初始化和執行。當然,核心庫也是開源的

Melang的核心庫中提供了很多演算法、資料結構、事件機制以及多程序多執行緒框架等介面,開發人員依託該函式庫進行開發不僅可以讓自身系統增加指令碼功能,還將會節省較大開發成本。

此外,若一個系統嵌入該核心庫並使用了該核心庫的事件介面來做非同步處理,那麼該系統在同一執行緒內,不僅可以做事件處理,還可以執行指令碼,兩者會交替進行,不會導致一方被阻而無法處理。

當然,也可以單獨使用Melang。Melang提供了基礎庫,除了常規字串和檔案系統以及網路IO操作外,還提供了訪問MySQL8的函式以及各類加解密、通訊等一系列功能。

小結

總體而言,雖然核心庫經歷了若干年變遷,但語言在行業內還是處於萌芽階段。因為定位於嵌入系統這一領域,因此也弱化了作為獨立語言而基礎庫不夠強大的短板。

此外,這款語言的核心庫中是自行實現了編譯原理相關的所有元件——詞法分析器、語法解析器生成器等,且使用極為方便,無需命令生成程式碼檔案。

順便說一句,這是一款國人開發的語言喔,期待各位多多關注多多支援。

感謝閱讀,如果您有好的想法或者意見建議,歡迎在下方留言評論或者私信碼哥。