Thực thi chiến lược đồng thời với hỗ trợ đa luồng JavaScript

Tác giả:FMZ~Lydia, Tạo: 2023-03-07 15:12:04, Cập nhật: 2023-09-18 20:04:21

Concurrent Strategy Execution with JavaScript Multithreading Support

Hãy cho chương trình chiến lược được thực hiện đồng thời, và thêm hỗ trợ nhiều luồng ở phía dưới của hệ thống để chiến lược JavaScript

Khi phát triển các chiến lược trên FMZ sử dụng ngôn ngữ JavaScript, vì kiến trúc chiến lược được khảo sát.exchange.Gofunction được sử dụng để thực hiện các cuộc gọi đồng thời đến một số giao diện, để đáp ứng các yêu cầu của một số kịch bản đồng thời. Nhưng nếu bạn muốn tạo một luồng duy nhất để thực hiện một loạt các hoạt động, nó là không thể. Ví dụ như ngôn ngữ Python, sử dụngthreadingthư viện để làm một số thiết kế đồng thời.

Dựa trên yêu cầu này, nền tảng FMZ đã nâng cấp lớp dưới của hệ thống.

  • Tạo các chủ đề để thực hiện các chức năng tùy chỉnh đồng thời.
  • Giao tiếp giữa các chuỗi.
  • Các biến được lưu trữ giữa các chủ đề được chia sẻ.
  • Chờ cho chủ đề hoàn thành thực thi để lấy lại tài nguyên và trả lại kết quả thực thi.
  • Tấn công sức mạnh và lấy lại tài nguyên.
  • Nhận ID chủ đề hiện tại trong hàm thực thi chủ đề đồng thời.

Tiếp theo, tôi sẽ đưa bạn để hiểu từng chức năng một một.

Tạo các chủ đề để thực thi các hàm tùy chỉnh đồng thời

Các__Threadfunction có thể tạo một chủ đề và thực thi một hàm đồng thời. ví dụ, bạn cần tạo một hàm đồng thờifunc1, điều gì làm chofunc1Chúng ta có thể để nó tích lũy từ 0 đến 9. Để xem quá trình tích lũy dần dần, chúng ta sử dụng vòng lặp for trong hàm func1 để tạm dừng mỗi lần (chức năng Sleep được sử dụng để ngủ trong một số lượng nhất định của milliseconds) trong một khoảng thời gian nhất định.

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

Trong các ứng dụng thực tế, chúng ta có thể thực hiện các yêu cầu http đồng thời như thế này:

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

Chờ cho kết thúc thực thi thread để lấy lại tài nguyên và trả về kết quả thực thi

Trong ví dụ trên, chúng tôi đã sử dụng__threadJoinchức năng trong chức năng chính cuối cùng để chờ cho các luồng đồng thời để hoàn thành thực thi.retnhận được giá trị trả về của__threadJoinhàm, và chúng tôi in giá trị trả về, chúng tôi có thể quan sát các kết quả cụ thể của việc thực hiện chuỗi đồng thời.

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

Kết thúc các thread bằng vũ lực và lấy lại tài nguyên

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
}

Chúng tôi vẫn sử dụng ví dụ ngay bây giờ, sau khi tạo một chủ đề, bạn có thể buộc phải chấm dứt việc thực hiện chủ đề sau khi chờ đợi 1 giây.

Truyền thông giữa các chủ đề

Truyền thông giữa các chuỗi chủ yếu sử dụng__threadPostMessagechức năng và__threadPeekMessageHãy xem ví dụ đơn giản sau:

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

Các__threadPostMessagefunction được sử dụng để gửi tin nhắn đến một thread. Parameter đầu tiên là ID của thread cụ thể để gửi đến, và tham số thứ hai là tin nhắn để gửi, có thể là một chuỗi, một giá trị, một mảng, hoặc một đối tượng JSON và vân vân. Tin nhắn có thể được gửi đến chủ đề chủ đề trong các hàm chủ đề đồng thời, và ID của chủ đề chủ đề được định nghĩa là 0.

Các__threadPeekMessagefunction được sử dụng để theo dõi thông điệp được gửi bởi một chủ đề nhất định. Parameter đầu tiên là để theo dõi ID cụ thể của chủ đề. Parameter thứ hai có thể thiết lập thời gian hết thời gian (trong milliseconds), hoặc nó có thể được thiết lập thành -1, có nghĩa là chặn, và nó sẽ không trở lại cho đến khi có một thông điệp. Chúng ta có thể nghe thông điệp được gửi bởi chủ đề chính đến chủ đề hiện tại trong hàm chủ đề đồng thời, và ID của chủ đề chính được định nghĩa là 0.

Tất nhiên, ngoại trừ các luồng liên lạc đồng thời với luồng chính, luồng liên lạc đồng thời cũng có thể liên lạc trực tiếp với nhau.

Nhận ID chủ đề hiện tại trong hàm thực thi chủ đề đồng thời

Trong ví dụ trên,var id = __threadId()được sử dụng, và__threadId()hàm có thể nhận được ID của chủ đề hiện tại.

Các biến được lưu trữ giữa các luồng chia sẻ

Ngoài giao tiếp giữa các chủ đề, các biến được chia sẻ cũng có thể được sử dụng để tương tác.

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
}

Điều trên là một minh chứng đơn giản của tất cả các hàm.

So sánh hiệu suất giữa JavaScript đa luồng gốc và WASM

Địa chỉ chiến lược thử nghiệm này:https://www.fmz.com/strategy/401463

Một cái nhìn, bạn có thể không biết chiến lược thử nghiệm này làm gì. Nó không quan trọng, hãy giải thích nó. Trước tiên, hãy tìm hiểu WASM là gì.


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

// thuật toán tái diễn của số Fibonacci trong ngôn ngữ C int fib ((int f) { if (f < 2) trả về f; trả lại fib ((f - 1) + fib ((f - 2); }

- JavaScript language version of the algorithm, fib function

// Một thuật toán tái diễn cho cùng một số Fibonacci, được viết bằng JavaScript hàm fib ((f) { if (f < 2) trả về f trả lại fib ((f - 1) + fib ((f - 2) }

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:

chức năng chính (() { // Để dễ dàng nhìn thấy mã, tôi viết bình luận về mã sau trực tiếp: cho cycle = 100 // Thử nghiệm thực hiện vòng lặp 100 lần let input = 30 // Các thông số sẽ được truyền đến hàm fib thuật toán để các chủ đề = [ __Thread(function(cycle, input) { // Một thread được tạo đồng thời để thực hiện tính toán bằng cách sử dụng phiên bản JavaScript của hàm fib hàm fib ((f) { // Các thuật toán cụ thể được sử dụng để kiểm tra, hàm fib if (f < 2) trả về f trả lại fib ((f - 1) + fib ((f - 2) } để ret = 0 cho (để i = 0; i < chu kỳ; i++) { // vòng lặp cho 100 lần ret = fib(input); // Gọi hàm fib của ngôn ngữ JavaScript Log (( Javascript tiến trình: , i) } trả về javascript fib: + ret }, chu kỳ, đầu vào),

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

// Algorithm recursive của số Fibonacci trong ngôn ngữ C int fib ((int f) { if (f < 2) trả về f; trả lại fib ((f - 1) + fib ((f - 2); }

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 thông tin #2 wasm fib: 832040 đã hết hạn: 13283.773019 2023-03-06 11:00:33 infomation #1 javascript fib: 832040 đã hết hạn: 21266.326974 It seems thatWasm` mất ít thời gian hơn và tốt hơn.


Nội dung liên quan

Nhiều hơn nữa