Cuando se desarrollan estrategias en FMZ utilizando el lenguaje JavaScript, ya que la arquitectura de la estrategia se encuesta.exchange.Go
la función se utiliza para hacer llamadas concurrentes a algunas interfaces, de modo que se cumplan los requisitos de algunos escenarios concurrentes. pero si desea crear un único hilo para realizar una serie de operaciones, es imposible. por ejemplo, como el lenguaje Python, utilizar elthreading
biblioteca para hacer algún diseño simultáneo.
Basándose en este requisito, la plataforma FMZ ha actualizado la capa inferior del sistema.
A continuación, voy a llevar a entender cada función una por una.
El__Thread
Por ejemplo, necesitas crear una función concurrentefunc1
, ¿qué hace elfunc1
Para ver el proceso de acumulación gradual, usamos el bucle for en la función func1 para pausar cada vez (la función Sleep se usa para dormir durante un cierto número de milisegundos) durante un cierto período de tiempo.
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)
}
En aplicaciones prácticas, podemos hacer peticiones http simultáneamente como esto:
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))
})
}
En el ejemplo anterior, utilizamos el__threadJoin
función en la función principal finalmente para esperar a que los hilos concurrentes terminen de ejecutar.ret
recibe el valor de retorno de la__threadJoin
función, y imprimimos el valor de retorno, podemos observar los resultados específicos de la ejecución de hilo concurrente.
// 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
}
Todavía usamos el ejemplo de ahora, después de crear un hilo, se puede terminar por la fuerza la ejecución del hilo después de esperar 1 segundo.
La comunicación entre hilos utiliza principalmente el__threadPostMessage
La función y el__threadPeekMessage
Veamos el siguiente ejemplo simple:
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)
}
}
El__threadPostMessage
El primer parámetro es el ID del hilo específico al que enviar, y el segundo parámetro es el mensaje a enviar, que puede ser una cadena, un valor, una matriz u objeto JSON, etc. Los mensajes se pueden enviar al hilo principal en funciones de hilo concurrentes, y el ID del hilo principal se define como 0.
El__threadPeekMessage
El segundo parámetro puede establecer el tiempo de tiempo de espera (en milisegundos), o se puede establecer en -1, lo que significa bloqueo, y no regresará hasta que no haya un mensaje. Podemos escuchar el mensaje enviado por el hilo principal al hilo actual en la función de hilo concurrente, y el ID del hilo principal se define como 0.
Por supuesto, excepto los hilos concurrentes que se comunican con el hilo principal. Los hilos concurrentes también pueden comunicarse entre sí directamente.
En el ejemplo anterior,var id = __threadId()
se utiliza, y el__threadId()
la función puede obtener el ID del hilo actual.
Además de la comunicación entre hilos, las variables compartidas también se pueden utilizar para la interacción.
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
}
Lo anterior es una demostración simple de todas las funciones.
Esta dirección de la estrategia de ensayo:https://www.fmz.com/strategy/401463
A simple vista, es posible que no sepa qué hace esta estrategia de prueba. No importa, explicémosla. Primero, aprendamos qué es WASM.
WebAssembly
esWASM
, WebAssembly
es un nuevo formato de codificación y puede ejecutarse en el navegador,WASM
puede utilizarse conJavaScript
coexiste, y WASM es más como un lenguaje de ensamblaje de bajo nivel.
Luego, la estrategia de prueba es comparar la eficiencia de ejecución de wasm y javascript, pero al comparar, los dos métodos de ejecución se pueden ejecutar sucesivamente, y se cuenta el tiempo de cada uno. También es posible permitir que los dos métodos de ejecución se ejecuten simultáneamente, y las estadísticas consumen tiempo. Ahora que se ha apoyado la implementación de concurrencia subyacente de la estrategia del lenguaje JavaScript, la estrategia de prueba utiliza un método concurrente para comparar naturalmente y comparar la velocidad de ejecución del mismo algoritmo.
// Recursive algorithm of Fibonacci Numbers in C Language
int fib(int f) {
if (f < 2) return f;
return fib(f - 1) + fib(f - 2);
}
// A recursive algorithm for the same Fibonacci numbers, written in JavaScript
function fib(f) {
if (f < 2) return f
return fib(f - 1) + fib(f - 2)
}
Se puede ver que la lógica de los dos algoritmos de la función fib es exactamente la misma.
function main() {
// In order to make it easier to see the code, I write the comment on the following code directly:
let cycle = 100 // The test executes the loop 100 times
let input = 30 // The parameters that will be passed to the algorithm fib function
let threads = [
__Thread(function(cycle, input) { // A thread is created concurrently to perform calculations using the JavaScript version of the fib function
function fib(f) { // The specific algorithm used for testing, the fib function
if (f < 2) return f
return fib(f - 1) + fib(f - 2)
}
let ret = 0
for (let i = 0; i < cycle; i++) { // loop for 100 times
ret = fib(input); // Call the fib function of the JavaScript language
Log("javascript progress: ", i)
}
return 'javascript fib: ' + ret
}, cycle, 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
})
}
En pocas palabras, WASM es un código de programa con una mayor eficiencia de ejecución. En el ejemplo, convertimos el código del lenguaje c de
Podemos usar el sitio web para convertir:https://wasdk.github.io/WasmFiddle/
// Recursive Algorithm of Fibonacci numbers in C Language
int fib(int f) {
if (f < 2) return f;
return fib(f - 1) + fib(f - 2);
}
Se pueden utilizar los siguientes comandos:
python -c "print('data:hex,'+bytes.hex(open('program.wasm','rb').read()))"
La cadena hexadecimal codificada eslet data = 'data:hex,0061736d0100000001868...
en el código.
Luego analizarlo en un modelo de la avispa a través de la funciónwasm.parseModule()
integrado por la FMZ.
Crear una instancia de modelo wasm a través de la funciónwasm.buildInstance()
integrado por la FMZ.
Entonces llama alfib
función en esta instancia del modelo wasm, a saber:ret = instance.callFunction('fib', input)
.
Esta estrategia de prueba sólo se puede utilizar para pruebas reales de bots. Las funciones de múltiples hilos de JavaScript no admiten backtesting hasta ahora.
wasm
yJavaScript
comparación de ejecución, los resultados finales de ejecución:
2023-03-06 11:00:33 infomation #2 wasm fib: 832040 elapsed: 13283.773019
2023-03-06 11:00:33 infomation #1 javascript fib: 832040 elapsed: 21266.326974
Parece quewasm
toma menos tiempo y es mejor.