JavaScript マルチスレッドディングサポートで同時に戦略を実行する

作者: リン・ハーンFMZ~リディア, 作成日:2023-03-07 15:12:04, 更新日:2023-09-18 20:04:21

Concurrent Strategy Execution with JavaScript Multithreading Support

JavaScript 戦略の底にマルチスレッドサポートを追加します.

FMZ で戦略を開発する際に JavaScript 言語を使用する. 戦略アーキテクチャが調査されているため.exchange.Goこの関数は,いくつかのインタフェースに同時呼び出しを行うために使用され,いくつかの同時シナリオの要件を満たします. しかし,一連の操作を実行するために単一のスレッドを作成したい場合は,それは不可能です.例えば,Python言語のように,threading図書室で並行設計をします

この要件に基づいて,FMZプラットフォームはシステムの底層をアップグレードした.JavaScript言語にも真のマルチスレッドサポートが追加された.詳細な機能には以下のものがある:

  • カスタム関数を同時に実行するスレッドを作成します.
  • 糸間通信
  • 共有スレッド間で保存される変数.
  • スレッドが実行を終えるまで待って リソースをリクエストして実行結果を返します
  • 糸を強制的に切って 資源を取り戻す
  • 同期スレッド実行関数で現在のスレッド ID を取得します.

次に,各関数を"つずつ説明します.

カスタム関数を同時に実行するスレッドを作成する

について__Thread例えば,同じ関数を作成する必要があります. この関数で,func1どこにいるの?func10 から 9 まで蓄積させることができます. 漸進的な蓄積プロセスを確認するために, func1 関数の for ループを使用して,毎回一時停止します (Sleep 関数は一定の数ミリ秒間眠るために使用されます).

function func1(sleepMilliseconds) {
    var sum = 0 
    for (var i = 0 ; i < 10 ; i++) {
        sum += i 
        Sleep(sleepMilliseconds)
        Log("sum:", sum)
    }
    
    return sum
}

function main() {
    // Use the __Thread function to create a thread concurrently, and the parameter 200 is the parameter of the func1 function,
    // If the func1 function has multiple parameters, here we pass the corresponding parameters.
    var thread1Id = __Thread(func1, 200)
    
    // Here we need to wait for the execution result of the thread whose thread Id is thread1Id, otherwise all threads will be released directly after the main function is executed.
    var ret = __threadJoin(thread1Id)
    Log("ret:", ret)
}

HTTP リクエストを同時に こんな感じで作成できます

function main() {
    let threads = [
        "https://www.baidu.com",
        "https://www.163.com"
    ].map(function(url) {
        return __Thread(function(url) {
            Log("GET", url)
            return HttpQuery(url)
        }, url)
    })
    threads.forEach(function(tid) {
        Log(__threadJoin(tid))
    })
}

リソースをリクリームして実行結果を返すためにスレッド実行の終了を待つ

この例では,__threadJoin実行が完了するまで待つ. 変数ret返回値が表示されます.__threadJoin同時にスレッドを実行する特定の結果を観察できます. 実行するときに,

// id: thread ID, terminated: whether it was forced to stop, elapsed: time-consuming (nanoseconds), ret: the return value of the thread execution function
ret: {"id":1,"terminated":false,"elapsed":2004884301,"ret":45}

糸を強制的に終了し,資源を取り戻す

function func1(sleepMilliseconds) {
    var sum = 0 
    for (var i = 0 ; i < 10 ; i++) {
        sum += i 
        Sleep(sleepMilliseconds)
        Log("sum:", sum)
    }
    
    return sum
}

function main() {
    var thread1Id = __Thread(func1, 200)
    Sleep(1000)
    retThreadTerminate = __threadTerminate(thread1Id)
    Log(retThreadTerminate)   // true
}

1秒間待った後 強制的にスレッドの実行を終了することができます. この例では,

スレッド間通信

スレッド間の通信は主に__threadPostMessage機能と__threadPeekMessage簡単な例を見てみましょう.

function func1() {
    var id = __threadId()
    while (true) {
        var postMsg = "Message from thread function func1" with "from id:" + id + 
        __threadPostMessage(0, postMsg)              // Send a message to the main thread
        var peekMsg = __threadPeekMessage(0)         // Receive messages from the main thread
        Log(peekMsg)
        Sleep(5000)
    }
}

function main() {
    var threadId = __Thread(func1)
    
    while (true) {
        var postMsg = "Messages from the main function of the main thread"
        __threadPostMessage(threadId, postMsg)
        var peekMsg = __threadPeekMessage(threadId)
        Log(peekMsg, "#FF0000")                     // #FF0000 , Set the log to red for distinction
        Sleep(5000)
    }
}

について__threadPostMessagefunction はスレッドにメッセージを送信するために使用される.最初のパラメータは送信する特定のスレッドのIDであり,第2パラメータは送信されるメッセージであり,文字列,値,配列,JSONオブジェクトなどである.メッセージは同時スレッド関数でメインスレッドに送信され,メインスレッドのIDは0と定義される.

について__threadPeekMessagefunction は特定のスレッドが送信したメッセージを監視するために使用されます.最初のパラメータはスレッドの特定のIDを監視することです.第2パラメータはタイムアウト時間を (ミリ秒で) 設定したり,ブロックすることを意味する -1 に設定したりできます.メッセージが来るまで戻らないでしょう.メインスレッドが現在のスレッドに送信したメッセージを並行スレッド関数で聞くことができ,メインスレッドのIDは0と定義されます.

もちろん,メインスレッドと通信する並行スレッドを除いて.並行スレッドも互いに直接通信することができます.

同期スレッド実行関数で現在のスレッドIDを取得する

この例では,var id = __threadId()使用されている場合,__threadId()この関数は,現在のスレッドのIDを取得できます.

共有スレッド間で格納される変数

スレッド間の通信に加えて,共有変数はインタラクションにも使用できます.

function testFunc() {
    __threadSetData(0, "testFunc", 100)   // Stored in the current thread environment, key-value pair testFunc : 100
    Log("testFunc execution completed")
}

function main() {
    // threadId is 1, the created thread with threadId 1 will be executed first, as long as the thread resources are not reclaimed, the variables stored locally in the thread will be valid
    var testThread = __Thread(testFunc)
    
    Sleep(1000)

    // export in main, get testFunc: 100
    Log("in main, get testFunc:", __threadGetData(testThread, "testFunc"))   // Take out the value whose key name is testFunc
}

上記は,すべての関数の簡単な実証です. 少し複雑なテスト例を見てみましょう.

ネイティブマルチスレッド JavaScript と WASM の性能比較

このテスト戦略のアドレス:https://www.fmz.com/strategy/401463

このテスト戦略が何をしているのか 一目でわからないかもしれません.どうでもいいです.説明しましょう.まず,WASMとは何かを知ろう.


Then the test strategy is to compare the execution efficiency of wasm and javascript, but when comparing, the two execution methods can be executed successively, and the time-consuming of each is counted. It is also possible to allow the two execution methods to execute concurrently, and the statistics are time-consuming. Now that the underlying concurrency implementation of the JavaScript language strategy has been supported, the test strategy uses a concurrent method to compare naturally and compare the execution speed of the same algorithm.

- Algorithm of C language version, fib function

// C言語でフィボナッチ数の再帰アルゴリズム int fib ((int f) { if (f < 2) は f を返します. fib (f - 1) + fib (f - 2) を返します { \ pos (192,220) }

- JavaScript language version of the algorithm, fib function

// 同じフィボナッチ数のための再帰アルゴリズム,JavaScriptで書かれています 函数 fib (f) { if (f < 2) は f を返します fib (f - 1) + fib (f - 2) を返します { \ pos (192,220) }

It can be seen that the logic of the two fib function algorithms is exactly the same. The following is the source code of the test strategy:

基本関数 (main)) { // コードを見るのを簡単にするために,私は直接次のコードのコメントを書きます: テストはループを100回実行します 算数 fib 関数に渡されるパラメータ スレッドを入力する __Thread(function(cycle, input) { // fib関数のJavaScriptバージョンを使用して計算を実行するために同時にスレッドが作成されます テストに使用される特定のアルゴリズム,fib関数 if (f < 2) は f を返します fib (f - 1) + fib (f - 2) を返します { \ pos (192,220) } ret = 0 とする. for (let i = 0; i < cycle; i++) { // 100 回ループする ret = fib(input); // JavaScript 言語の fib 関数を呼び出す ログ (JavaScriptの進捗状況: ,i) { \ pos (192,220) } 返信 JavaScript fib: + ret },サイクル,インプット)

    __Thread(function(cycle, input) {           // Run a thread concurrently to perform calculations using the wasm version of the fib function
        let data = 'data:hex,0061736d010000000186808080000160017f017f0382808080000100048480808000017000000583808080000100010681808080000007908080800002066d656d6f727902000366696200000aa480808000019e80808000000240200041024e0d0020000f0b2000417f6a10002000417e6a10006a0b'
        let m = wasm.parseModule(data)          // The data variable is the hex string of the wasm-encoded C language fib function, and the wasm model m is created using wasm.parseModule

        let instance = wasm.buildInstance(m, {  // Model instantiation, allocate a certain stack space
            stack_size: 65 * 1024 * 1024,
        })

        let ret = 0
        for (let i = 0; i < cycle; i++) {                // loop for 100 times 
            ret = instance.callFunction('fib', input)    // Calling the fib function code in the wasm instance is equivalent to calling the int fib(int f) function 
            Log("wasm progress: ", i)
        }

        return 'wasm fib: ' + ret
    }, cycle, input)
]

// The elements in the threads array are the IDs returned by the __Thread function
threads.forEach(function(tid) {
    let info = __threadJoin(tid)                         // Use the __threadJoin function to wait for two concurrent threads to execute and get the execution result
    Log('#'+tid, info.ret, 'elapsed:', info.elapsed / 1e6, "#ff0000")   // output execution result
})

}

Simply put, WASM is a program code with higher execution efficiency. In the example, we convert the c language code of "Fibonacci number recursive algorithm" into WASM. The process is like this:

1. Compile a piece of C language function code into wasm code.

We can use the website to convert: https://wasdk.github.io/WasmFiddle/

C言語でフィボナッチ数に関する再帰アルゴリズム int fib ((int f) { if (f < 2) は f を返します. fib (f - 1) + fib (f - 2) を返します { \ pos (192,220) }

2. Further encode the wasm code into a hex string.

The following commands can be used:

Python -c print ((data:hex,+bytes.hex)) オープン ((program.wasm,rb).読める))

The encoded hex string is ```let data = 'data:hex,0061736d0100000001868...``` in the code.

3. Then parse it into a wasm model through the function ```wasm.parseModule()``` integrated by FMZ.

4. Create a wasm model instance through the function ```wasm.buildInstance()``` integrated by FMZ.

5. Then call the ```fib``` function in this wasm model instance, namely: ```ret = instance.callFunction('fib', input)```.

## Create a real bot to run the test
This test strategy can only be used for real bot testing. JavaScript multi-threading functions do not support backtesting so far.

```wasm``` and ```JavaScript``` execution comparison, the final execution results:

2023-03-06 11:00:33 インフォメーション#2 wasm fib: 832040 経過: 13283.773019 2023-03-06 11:00:33 インフォメーション# 1 javascript fib: 832040 経過: 21266.326974 It seems that時間がかかり,より良くなります.


関連コンテンツ

もっと見る