В процессе загрузки ресурсов... загрузка...

Одновременное выполнение стратегии с поддержкой JavaScript для многопотока

Автор:FMZ~Lydia, Создано: 2023-03-07 15:12:04, Обновлено: 2023-09-18 20:04:21

img

Пусть программа стратегии выполняется одновременно, и добавить поддержку многопотока в нижней части системы к стратегии JavaScript

При разработке стратегий на FMZ с использованием языка JavaScript, поскольку архитектура стратегии опрошена.exchange.Goфункция используется для одновременных вызовов на некоторые интерфейсы, чтобы удовлетворить требования некоторых одновременных сценариев. Но если вы хотите создать одну нить для выполнения серии операций, это невозможно. Например, как язык Python, используйтеthreadingБиблиотека для одновременного проектирования.

Основываясь на этом требовании, платформа FMZ обновила нижний слой системы.

  • Создавать потоки для одновременного выполнения пользовательских функций.
  • Связь между нитями.
  • Переменные, хранящиеся между общими потоками.
  • Подождите, пока нить закончит выполнение, чтобы восстановить ресурсы и вернуть результат выполнения.
  • Навязываем нить силой и возвращаем ресурсы.
  • Получить текущий ID потока в функции одновременного выполнения потока.

Далее я приведу вас к пониманию каждой функции одну за другой.

Создание потоков для одновременного выполнения пользовательских функций

В__Threadфункция может создавать нить и выполнять функцию одновременно.func1, что делаетfunc1Чтобы увидеть процесс постепенного накопления, мы используем петлю for в функции func1 для паузы каждый раз (функция Sleep используется для сна на определенное количество миллисекунд) в течение определенного периода времени.

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

В практических приложениях мы можем делать HTTP запросы одновременно вот так:

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

Подождите окончания выполнения потока, чтобы восстановить ресурсы и вернуть результат выполнения

В приведенном выше примере мы использовали__threadJoinфункция в основной функции, наконец, дождаться, пока одновременные потоки закончат выполнение.retполучает возвращенное значение__threadJoinфункция, и мы печатаем возвращаемое значение, мы можем наблюдать конкретные результаты одновременного выполнения потока.

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

Мы все еще используем пример прямо сейчас, после создания потока, вы можете насильно прекратить исполнение потока после ожидания 1 секунды.

Межпоточная связь

Межпоточная связь в основном использует__threadPostMessageФункция и__threadPeekMessageДавайте посмотрим на следующий простой пример:

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

В__threadPostMessagefunction используется для отправки сообщения в нить. Первый параметр - это идентификатор конкретной нитки для отправки, а второй параметр - это сообщение, которое должно быть отправлено, которое может быть строкой, значением, массивом или объектом JSON и так далее. Сообщения могут быть отправлены в основную нить в одновременных функциях нитки, а идентификатор основной нитки определяется как 0.

В__threadPeekMessagefunction используется для мониторинга сообщения, отправленного определенной нитью. Первый параметр - это мониторинг конкретного ID нитки. Второй параметр может устанавливать время выхода (в миллисекундах), или он может быть установлен на -1, что означает блокировку, и он не вернется, пока не будет сообщения. Мы можем слушать сообщение, отправленное главной нитью текущей нитке в функции параллельной нитки, и ID главной нитки определяется как 0.

Конечно, за исключением параллельных потоков, которые общаются с основной нитью.

Получить ID текущего потока в функции одновременного выполнения потока

В примере выше,var id = __threadId()используется, и__threadId()Функция может получить идентификатор текущей нитки.

Переменные, хранящиеся между общими потоками

В дополнение к коммуникации между потоками, общие переменные также могут использоваться для взаимодействия.

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
}

Выше приведенная простая демонстрация всех функций. Давайте посмотрим на немного более сложный пример теста.

Сравнение производительности между нативным многопоточным JavaScript и WASM

Эта стратегия испытаний адресуется:https://www.fmz.com/strategy/401463

На первый взгляд, вы можете не знать, что делает эта стратегия тестирования. Это не имеет значения, давайте объясним. Во-первых, давайте узнаем, что такое WASM.

WebAssemblyэтоWASM, WebAssemblyявляется новым форматом кодирования и может работать в браузере,WASMможет использоваться сJavaScriptсосуществует, и WASM больше похож на язык сборки низкого уровня.

Затем стратегия тестирования заключается в сравнении эффективности исполнения wasm и javascript, но при сравнении два метода исполнения могут быть выполнены последовательно, и время, затрачиваемое каждым из них, подсчитывается. Также можно позволить двум методам исполнения выполнять одновременно, а статистика занимает много времени. Теперь, когда подлежащая одновременной реализации стратегии языка JavaScript поддерживается, стратегия тестирования использует одновременный метод для естественного сравнения и сравнения скорости исполнения одного и того же алгоритма.

  • Алгоритм версии языка C, функция fib
// Recursive algorithm of Fibonacci Numbers in C Language
int fib(int f) {
    if (f < 2) return f;
    return fib(f - 1) + fib(f - 2);
}
  • Версия алгоритма на языке JavaScript, функция fib
// 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)
}

Можно увидеть, что логика двух алгоритмов функции fib точно такая же.

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

Проще говоря, WASM - это программный код с более высокой эффективностью исполнения. В примере мы преобразуем код языка c Фибоначчи рекурсивный алгоритм числа в WASM. Процесс выглядит следующим образом:

  1. Компилировать фрагмент кода функции языка C в WASM код.

Мы можем использовать сайт для конвертации: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);
}
  1. Далее закодируйте код в шестерковой строке.

Можно использовать следующие команды:

python -c "print('data:hex,'+bytes.hex(open('program.wasm','rb').read()))"

Кодированная шестерковая строкаlet data = 'data:hex,0061736d0100000001868...в коде.

  1. Затем проанализируйте его в моделе оса с помощью функцииwasm.parseModule()интегрированный FMZ.

  2. Создать экземпляр модели wasm с помощью функцииwasm.buildInstance()интегрированный FMZ.

  3. Тогда позвониfibфункция в данном примере модели wasm, а именно:ret = instance.callFunction('fib', input).

Создать настоящего бота для выполнения теста

Эта стратегия тестирования может использоваться только для реального тестирования ботов.

wasmиJavaScriptсравнение выполнения, окончательные результаты выполнения:

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

Кажется, чтоwasmЭто занимает меньше времени и лучше.


Связанные

Больше