Eksekusi strategi bersamaan dengan dukungan multithreading JavaScript

Penulis:FMZ~Lydia, Dibuat: 2023-03-07 15:12:04, Diperbarui: 2023-09-18 20:04:21

Concurrent Strategy Execution with JavaScript Multithreading Support

Biarkan program strategi dijalankan secara bersamaan, dan tambahkan dukungan multi-thread di bagian bawah sistem ke strategi JavaScript

Ketika mengembangkan strategi di FMZ menggunakan bahasa JavaScript, karena arsitektur strategi disurvei.exchange.Gofungsi digunakan untuk membuat panggilan serentak ke beberapa antarmuka, sehingga memenuhi persyaratan beberapa skenario serentak. tapi jika Anda ingin membuat thread tunggal untuk melakukan serangkaian operasi, itu tidak mungkin. misalnya seperti bahasa Python, menggunakanthreadingperpustakaan untuk melakukan beberapa desain paralel.

Berdasarkan persyaratan ini, platform FMZ telah memperbarui lapisan bawah sistem. dukungan multithreading sejati juga telah ditambahkan ke bahasa JavaScript.

  • Buat thread untuk mengeksekusi fungsi kustom secara bersamaan.
  • Komunikasi antar benang.
  • Variabel yang disimpan di antara thread bersama.
  • Tunggu thread selesai menjalankan untuk merebut kembali sumber daya dan mengembalikan hasil eksekusi.
  • Dengan paksa mengakhiri benang dan merebut kembali sumber daya.
  • Dapatkan ID thread saat ini dalam fungsi eksekusi thread bersamaan.

Selanjutnya, saya akan membawa Anda untuk memahami setiap fungsi satu per satu.

Buat thread untuk menjalankan fungsi kustom secara bersamaan

Peraturan__Threadfungsi dapat membuat thread dan mengeksekusi fungsi secara bersamaan.func1, apa yang dilakukanfunc1Untuk melihat proses akumulasi secara bertahap, kita menggunakan loop for dalam fungsi func1 untuk berhenti setiap kali (fungsi Sleep digunakan untuk tidur selama sejumlah milidetik) untuk periode waktu tertentu.

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

Dalam aplikasi praktis, kita dapat membuat permintaan http secara bersamaan seperti ini:

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

Tunggu hingga akhir thread eksekusi untuk merebut kembali sumber daya dan mengembalikan hasil eksekusi

Dalam contoh di atas, kami menggunakan__threadJoinfungsi dalam fungsi utama akhirnya untuk menunggu thread bersamaan untuk menyelesaikan pelaksanaan.retmenerima nilai kembali dari__threadJoinfungsi, dan kita mencetak nilai kembali, kita dapat mengamati hasil spesifik dari pelaksanaan thread bersamaan.

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

Hentikan thread dengan paksa dan dapatkan kembali sumber daya

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
}

Kami masih menggunakan contoh saat ini, setelah membuat thread, Anda dapat memaksa mengakhiri eksekusi thread setelah menunggu selama 1 detik.

Komunikasi antar thread

Komunikasi antar thread terutama menggunakan__threadPostMessageFungsi dan__threadPeekMessageMari kita lihat contoh sederhana berikut:

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

Peraturan__threadPostMessagefungsi digunakan untuk mengirim pesan ke thread. Parameter pertama adalah ID thread tertentu untuk dikirim ke, dan parameter kedua adalah pesan yang akan dikirim, yang dapat menjadi string, nilai, array, atau objek JSON dan sebagainya. Pesan dapat dikirim ke thread utama dalam fungsi thread paralel, dan ID thread utama didefinisikan sebagai 0.

Peraturan__threadPeekMessagefunction digunakan untuk memantau pesan yang dikirim oleh thread tertentu. Parameter pertama adalah untuk memantau ID spesifik thread. Parameter kedua dapat mengatur waktu timeout (dalam milidetik), atau dapat diatur menjadi -1, yang berarti memblokir, dan tidak akan kembali sampai ada pesan. Kita dapat mendengarkan pesan yang dikirim oleh thread utama ke thread saat ini dalam fungsi thread paralel, dan ID thread utama didefinisikan sebagai 0.

Tentu saja, kecuali thread paralel yang berkomunikasi dengan thread utama. thread paralel juga dapat berkomunikasi satu sama lain secara langsung.

Dapatkan ID thread saat ini dalam fungsi eksekusi thread bersamaan

Dalam contoh di atas,var id = __threadId()digunakan, dan__threadId()fungsi dapat mendapatkan ID dari thread saat ini.

Variabel yang disimpan di antara thread bersama

Selain komunikasi antara thread, variabel bersama juga dapat digunakan untuk interaksi.

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
}

Di atas adalah demonstrasi sederhana dari semua fungsi. mari kita lihat contoh tes yang sedikit lebih rumit.

Perbandingan kinerja antara JavaScript multi-threaded asli dan WASM

Alamat strategi uji ini:https://www.fmz.com/strategy/401463

Pada pandangan pertama, Anda mungkin tidak tahu apa yang dilakukan strategi uji ini. Tidak masalah, mari kita jelaskan. Pertama, mari kita pelajari apa itu 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

// Algoritma rekursif dari Angka Fibonacci dalam Bahasa C Int fib ((int f) { jika (f < 2) mengembalikan f; kembali fib ((f - 1) + fib ((f - 2); {\cH00FFFF}

- JavaScript language version of the algorithm, fib function

// Sebuah algoritma rekursif untuk nomor Fibonacci yang sama, ditulis dalam JavaScript fungsi fib ((f) { jika (f < 2) mengembalikan f kembali fib ((f - 1) + fib ((f - 2) {\cH00FFFF}

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:

Fungsi utama Untuk memudahkan melihat kode, saya menulis komentar pada kode berikut secara langsung: let cycle = 100 // Ujiannya menjalankan loop 100 kali let input = 30 // Parameter yang akan diteruskan ke fungsi algoritma fib biarkan thread = [ __Thread(function(cycle, input) { // Sebuah thread dibuat secara bersamaan untuk melakukan perhitungan menggunakan versi JavaScript dari fungsi fib fungsi fib ((f) { // Algoritma spesifik yang digunakan untuk pengujian, fungsi fib jika (f < 2) mengembalikan f kembali fib ((f - 1) + fib ((f - 2) {\cH00FFFF} let ret = 0 untuk (biarkan i = 0; i < siklus; i++) { // loop untuk 100 kali ret = fib(input); // Panggilan fungsi fib dari bahasa JavaScript Log (( Javascript kemajuan: , i) {\cH00FFFF} return javascript fib: + ret }, siklus, input),

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

// Algoritma rekursif dari bilangan Fibonacci dalam Bahasa C Int fib ((int f) { jika (f < 2) mengembalikan f; kembali fib ((f - 1) + fib ((f - 2); {\cH00FFFF}

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).read()))

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 wasm fib: 832040 telah berlalu: 13283.773019 2023-03-06 11:00:33 infomation #1 javascript fib: 832040 telah berakhir: 21266.326974 It seems thatWasm` membutuhkan waktu lebih sedikit dan lebih baik.


Artikel terkait

Informasi lebih lanjut