Gleichzeitige Strategieausführung mit JavaScript-Multithreading-Unterstützung

Schriftsteller:FMZ~Lydia, Erstellt: 2023-03-07 15:12:04, Aktualisiert: 2023-09-18 20:04:21

Concurrent Strategy Execution with JavaScript Multithreading Support

Lassen Sie das Strategieprogramm gleichzeitig ausgeführt werden, und fügen Sie Multi-Thread-Unterstützung am Ende des Systems zu der JavaScript-Strategie

Bei der Entwicklung von Strategien auf FMZ mit der JavaScript-Sprache, da die Strategie-Architektur befragt wird.exchange.GoFunktion wird verwendet, um gleichzeitige Aufrufe an einige Schnittstellen zu tätigen, um die Anforderungen einiger gleichzeitiger Szenarien zu erfüllen.threadingBibliothek, um gleichzeitig etwas zu entwerfen.

Aufgrund dieser Anforderung hat die FMZ-Plattform die untere Schicht des Systems aktualisiert.

  • Erstellen Sie Threads, um benutzerdefinierte Funktionen gleichzeitig auszuführen.
  • Kommunikation zwischen Threads.
  • Variablen, die zwischen geteilten Threads gespeichert werden.
  • Warten Sie, bis der Thread die Ausführung beendet hat, um Ressourcen zurückzufordern und das Ausführungsresultat zurückzugeben.
  • Wir müssen den Faden zwangsweise beenden und Ressourcen zurückfordern.
  • Erhalten Sie die aktuelle Thread-ID in der gleichzeitigen Thread-Ausführungsfunktion.

Als Nächstes werde ich Sie dazu bringen, jede Funktion einzeln zu verstehen.

Erstellen von Threads zur gleichzeitigen Ausführung von benutzerdefinierten Funktionen

Die__ThreadFunktion kann einen Thread erstellen und eine Funktion gleichzeitig ausführen.func1, was macht diefunc1Wir können es von 0 bis 9 akkumulieren lassen. Um den schrittweisen Akkumulationsprozess zu sehen, verwenden wir die For-Schleife in der Funktion func1 um jedes Mal (die Sleep-Funktion wird für eine bestimmte Anzahl von Millisekunden zum Schlafen verwendet) für einen bestimmten Zeitraum zu pausieren.

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)
}

In praktischen Anwendungen können wir http-Anfragen gleichzeitig so machen:

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))
    })
}

Warten Sie auf das Ende der Thread-Ausführung, um Ressourcen zurückzufordern und das Ausführungsergebnis zurückzugeben

In dem obigen Beispiel haben wir die__threadJoinFunktion in der Hauptfunktion endlich warten, bis die gleichzeitigen Threads zu beenden ausführen.reterhält den Rückgabewert der__threadJoinFunktion, und wir drucken den Rückgabewert, können wir die spezifischen Ergebnisse der gleichzeitigen Thread-Ausführung beobachten.

// 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}

Endet den Thread mit Gewalt und holt die Ressourcen zurück.

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
}

Wir verwenden immer noch das Beispiel gerade jetzt, nachdem Sie einen Thread erstellt haben, können Sie die Ausführung des Threads nach einem Wartezeitraum von 1 Sekunde zwangsweise beenden.

Kommunikation zwischen Threads

Die Inter-Thread-Kommunikation nutzt hauptsächlich die__threadPostMessageFunktion und__threadPeekMessageWir wollen uns das folgende einfache Beispiel ansehen:

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)
    }
}

Die__threadPostMessageDer erste Parameter ist die ID des spezifischen Threades, an den gesendet werden soll, und der zweite Parameter ist die zu versendende Nachricht, die eine Zeichenfolge, ein Wert, ein Array oder ein JSON-Objekt sein kann. Nachrichten können in gleichzeitigen Threadfunktionen an den Hauptthread gesendet werden, und die ID des Hauptthreads ist als 0 definiert.

Die__threadPeekMessageDer erste Parameter ist die Überwachung der spezifischen ID des Threads. Der zweite Parameter kann die Timeout-Zeit (in Millisekunden) festlegen, oder er kann auf -1 gesetzt werden, was bedeutet, dass er blockiert wird, und er wird nicht zurückkehren, bis es eine Nachricht gibt. Wir können die Nachricht hören, die vom Hauptthread an den aktuellen Thread in der gleichzeitigen Thread-Funktion gesendet wird, und die ID des Hauptthreads ist als 0 definiert.

Natürlich, mit Ausnahme von gleichzeitigen Threads, die mit dem Hauptthread kommunizieren. Gleichzeitige Threads können auch direkt miteinander kommunizieren.

Erhalten Sie die aktuelle Thread-ID in der gleichzeitigen Thread-Ausführung

In dem obigen Beispielvar id = __threadId()Die__threadId()Funktion kann die ID des aktuellen Threads erhalten.

Variablen zwischen geteilten Threads gespeichert

Zusätzlich zur Kommunikation zwischen Threads können geteilte Variablen auch für die Interaktion verwendet werden.

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
}

Das ist eine einfache Demonstration aller Funktionen. Schauen wir uns ein etwas komplizierteres Testbeispiel an.

Leistungsvergleich zwischen nativen mehrthreaded JavaScript und WASM

Diese Teststrategie richtet sich an:https://www.fmz.com/strategy/401463

Auf den ersten Blick wissen Sie vielleicht nicht, was diese Teststrategie bewirkt.Es spielt keine Rolle, lassen Sie uns es erklären.Zuerst lernen wir, was WASM ist.


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

// Rekursiver Algorithmus von Fibonacci-Zahlen in C-Sprache In den meisten Fällen wird die wenn (f < 2) f zurückgibt; Rücksendung fib ((f - 1) + fib ((f - 2); - Ich weiß.

- JavaScript language version of the algorithm, fib function

// Ein rekursiver Algorithmus für die gleichen Fibonacci-Zahlen, in JavaScript geschrieben Funktion fib ((f) { wenn (f < 2) f zurückgibt Rückgabe von fib ((f - 1) + fib ((f - 2) - Ich weiß.

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:

Funktion main() { // Um es einfacher zu machen, den Code zu sehen, schreibe ich den Kommentar direkt auf den folgenden Code: let cycle = 100 // Der Test führt die Schleife 100 Mal aus let input = 30 // Die Parameter, die an die Algorithmus-Fib-Funktion übergeben werden lassen Sie Fäden = [ __Thread(function(cycle, input) { // Ein Thread wird gleichzeitig erstellt, um Berechnungen mit der JavaScript-Version der Funktion fib durchzuführen Funktion fib ((f) { // Der spezifische Algorithmus, der für das Testen verwendet wird, die Funktion fib wenn (f < 2) f zurückgibt Rückgabe von fib ((f - 1) + fib ((f - 2) - Ich weiß. let ret = 0 für (laßt i = 0; i < Zyklus; i++) { // Schleife für 100 Mal Ret = fib(input); // Die Funktion fib der JavaScript-Sprache aufrufen Log (( Javascript Fortschritt: , i) - Ich weiß. Rückgabe javascript fib: + ret }, Zyklus, Eingabe)

    __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/

// Rekursiver Algorithmus der Fibonacci-Zahlen in C-Sprache In den meisten Fällen wird die wenn (f < 2) f zurückgibt; Rücksendung fib ((f - 1) + fib ((f - 2); - Ich weiß.

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

The following commands can be used:

Python -c print(data:hex,+bytes.hex(open(program.wasm,rb).lesen)))

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 Infomation #2 warm fib: 832040 vergangen: 13283.773019 2023-03-06 11:00:33 Infomation #1 javascript fib: 832040 abgelaufen: 21266.326974 It seems thatWasm` dauert weniger Zeit und ist besser.


Inhalte dazu

Weitere Informationen