Concurrent Strategy Execution with JavaScript Multithreading Support

Concurrent Strategy Execution with JavaScript Multithreading Support
Atom
4/17/2024


When developing strategies on FMZ using the JavaScript language, since the strategy architecture is polled. If there is a concurrent design scenario, the ```exchange.Go``` function is used to make concurrent calls to some interfaces, so as to meet the requirements of some concurrent scenarios. But if you want to create a single thread to perform a series of operations, it is impossible. For example, like the Python language, use the ```threading``` library to do some concurrent design.

Based on this requirement, the FMZ platform has upgraded the bottom layer of the system. True multithreading support has also been added to the JavaScript language. Detailed features include:

- Create threads to execute custom functions concurrently.
- Inter-thread communication.
- Variables stored between shared threads.
- Wait for the thread to finish executing to reclaim resources and return the execution result.
- Forcibly end the thread and reclaim resources.
- Get the current thread ID in the concurrent thread execution function.

Next, I will take you to understand each function one by one.

Create threads to execute custom functions concurrently
The ```__Thread``` function can create a thread and execute a function concurrently. For example, you need to create a concurrent function ```func1```, what does the ```func1``` function do? We can let it accumulate from 0 to 9. In order to see the gradual accumulation process, we use the for loop in the func1 function to pause each time (the Sleep function is used to sleep for a certain number of milliseconds) for a certain period of time.
```
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 practical applications, we can make http requests concurrently like this:
```
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))
})
}
```
Wait for the end of thread execution to reclaim resources and return the execution result
In the above example, we used the ```__threadJoin``` function in the main function finally to wait for the concurrent threads to finish executing. The variable ```ret``` receives the return value of the ```__threadJoin``` function, and we print the return value, we can observe the specific results of the concurrent thread execution.
```
// 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}
```
End the thread forcibly and reclaim resources
```
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
}
```
We still use the example just now, after creating a thread, you can forcibly terminate the execution of the thread after waiting for 1 second.

Inter-thread communication
Inter-thread communication mainly uses the ```__threadPostMessage``` function and the ```__threadPeekMessage``` function. Let's look at the following simple example:
```
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() // Receive messages from other threads
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)
}
}
```
The ```__threadPostMessage``` function is used to send a message to a thread. The first parameter is the ID of the specific thread to send to, and the second parameter is the message to be sent, which can be a string, a value, an array, or a JSON object and so on. Messages can be sent to the main thread in concurrent thread functions, and the ID of the main thread is defined as 0.

The ```__threadPeekMessage``` function is used to monitor the message sent by a certain thread. It can set the timeout time (in milliseconds), or it can be set to 0, which means blocking, and it will not return until there is a message.

Of course, except for concurrent threads communicating with the main thread. Concurrent threads can also communicate with each other directly.

Get the current thread ID in the concurrent thread execution function
In the above example, the function ```var id = __threadId(),__threadId()``` is used to get the ID of the current thread.

Variables stored between shared threads
In addition to communication between threads, shared variables can also be used for interaction.
```
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
}
```
The above is a simple demonstration of all functions.

From: https://blog.mathquant.c...javascript-strategy.html




Attach files by dragging & dropping, , or pasting from the clipboard.

loading
clippy