В этом разделе вы найдете пример использования объекта Thread
Объект Thread предназначен для выполнения вычислений в отдельном потоке
JS Объект Thread запускает контекст выполнения в отдельном потоке
и ждет внешние запросы на выполнение из основного поста, где он был создан.
При создании объекта Thread в аргументах указывается js файл с функциями, которые нужно выполнять в отдельном потоке
post.evalScript('jcjsHelper.js')
// функция которая будет выполнятся в отдельном потоке
function main(arg1,arg2,arg3) {
console.log(arg1,arg2,arg3)
return {arg1: arg1, arg2: arg2, arg3: arg3, tm: +new Date()}
}
// выполнить очистку коннтенкста при завершении потока
// thisThread - это ссылка на выполняющийся в этот момент поточный объект
thisThread.halt.connect(post, function() {
function clear(ob){
var all = jsext.keys(ob, true), k
while(all.length) {
k = all.shift()
if(!ifFunction(ob[k].deleteLater)) continue
ob[k].deleteLater()
delete ob[k]
}
}
clear(post)
})
post.evalScript('jcjsHelper.js')
//Если файл не найден, то будет создан js exception
var thr = new Thread('init_thr.js')
function callBack(ret){ // функция, вызываемая при завершении функции init_thr.js: main()
var objDesc = arguments[arguments.length - 1]
// последний аргумент всегда содержит в себе объект objDesc
//{"error":0,"file":"init_thr.js","fn":"main","thread":"0x3145750"}
// ret содержит объект который вернула функция init_thr.js: main()
// {arg1: 'string1, arg2: {obj1: 1}, arg3: 1, tm: 12234353252345}
var ar = [].slice.call(arguments)
post.log(JSON.stringify(ar))
}
var arg1 = 'string1';
var arg2 = {obj1: 1};
var arg3 = 1;
thr.eval('main', callBack, [arg1,arg2,arg3]) // отправить в поток
//если указана дефолтная функция, то 'main' можно не указывать
thr.eval(callBack, [arg1,arg2,arg3])
//порядок аргументов не имеет значения. eval автоматически их распознает
thr.eval([arg1,arg2,arg3], callBack)
thr.eval([arg1,arg2,arg3], callBack, 'main')
new Thread(jsFile, jsFuncName) Создать объект
jsFile: имя файла, в котором объявлена функция с именем jsFuncName
Внимание!!! jsFuncName не может содержать небуквенные символы,
иначе эта строка будет назначена именем объекта.
Следущюю функцию неудастся запустить из основного контекста
function f_1(){}
var thr = new Thread('init_thr.js', 'funcHash'); // Создать объект
Пример использования:
var thr = new Thread('init_thr.js', 'funcHash'); // Создать объект
thr.debug = 1 // включить отладочный вывод в терминальное окно
bool thr.isRunning Только чтение
Поток выполняется
bool thr.isFinished Только чтение
Поток не выполняется
variant thr.isEvaluate Только чтение
Выполняется поточная функция (возвращает имя выполняемой функции или false если не выполняется)
String thr.threadId
Возвращает идентификатор потока, в котором выполняется JS контекст
post.log('i', thisThread.threadId ) // в поточном контексте
post.log('i', thr.threadId ) // в основном потоке
// выведет в log '0x1891c70' или '' если поток не работает
bool thr.debug Только чтение
Разрешить вывод в терминал отладочной информации
void thr.jsQueue_idle(thisThread);
генерируется объектом Thread при отсутствия поступление команд на конвеер выполнения более чем 120 сек
// подсоединить к сигналу jsQueue_idle функцию обработчик
thr.jsQueue_idle.connect(function(sender){
post.log('простаивание, удалить поток')
sender.deleteLater()
thr = null
})
генерируется объектом Thread непосредственно перед удалением объекта и только в случае удаления объекта в момент выполнения задания в поточном контексте После этого сигнала слудует сигнал thr.destroy(thisThread)
thr.destroy.connect(function(sender){
post.log('объект '+sender+' удален окончательно')
thr = null
})
генерируется объектом Thread непосредственно перед удалением объекта
thr.destroy.connect(function(sender){
post.log('объект '+sender+' удален окончательно')
thr = null
})
генерируется объектом Thread после запуска потока и загрузки js файла в поточный контекс.
После этого сигнала объект готов к приему команд на выполнение
thr.isEval.connect(function(sender){
post.log('объект '+sender+' удален окончательно')
thr = null
})
генерируется объектом Thread если в момент выполнания возникили ошибки
thr._exception.connect(function(errMsg){
post.log('возникла ошибка: '+errMsg)
thr = null
})
bool thr.eval(fnName, argArr, ctxObj, callBackFn) Функция
Главная функция. Отправить на выполнение в поток
var thr = new Thread('init_thr.js', 'main')
function callBack(ret){ // функция, вызываемая при завершении функции init_thr.js: main()
// ret содержит объект который вернула функция init_thr.js: main()
// вывод в лог всех аргументов
// var ar = [].slice.call(arguments); post.log(JSON.stringify(ar))
var objDesc = arguments[arguments.length - 1]
// последний аргумент всегда содержит в себе объект objDesc
//{"error":0,"file":"init_thr.js","fn":"main","thread":"0x3145750"}
post.log(JSON.stringify(objDesc))
// обработка ошибок вариант 1
if(arguments.length !== 2) return post.log('e', 'Error')
// обработка ошибок вариант 2
if(objDesc.error) return post.log('e', 'Error')
post.log('i', 'OK ' + (this === selfObject)) // выведет в лог 'OK true'
}
var selfObject = {}
thr.eval(callBack, [1,2,3], selfObject, 'main') // отправить в поток
// или отправить без названия функции, т.к. она объявлена дефолтной при создании объекта
thr.eval(callBack, [1,2,3], selfObject)
void thr.start() Процедура
Запустить поток (запускается автоматически при создании объекта).
Если поток остановлен по причине отсутствия активности, необходимо его
запустить этой функцией перед отправкой заданий на элеватор выполнения
void thr.stop() Процедура
Остановить поток и дождаться его завершения
void thr.go_stop() Процедура
Остановить поток не дожидаясь его завершения
int thr.tasksSize() Функция
Получить количество заданий в очереди
if(typeof QFileInfo !== 'function') post.install('QFileInfo')
var finfo = new QFileInfo('init_thr.js')
var thr = new Thread(finfo, 'Thread name 1')
// создать свойство tasks, которое возвращает результат функции tasksSize()
Object.defineProperty(thr, 'tasks', {get: function(){return this.tasksSize()}, enumerable: 0, configurable: 1})
post.log('i', 'tasksSize = ' + thr.tasks) // выведет в log 'tasksSize = 0'
Для удобства использования создан js хелпер с классом PoolThread,
позволяющий автоматически следить за количеством потоков и
подстраиваться к нагрузке и возможностям CPU (количество ядер)
PoolThread предоставляет пулинг объектов Thread и также имеет функцию eval c таким-же
синтаксисом как и Thread.eval(). Отличие состоит только в том, что при вызове создается пул потоков,
количество которых зависит от частоты вызова функции PoolThread.eval() и занятости находящихся в пуле потоков.
// подгрузить хелпер
post.evalScript('jcjsHelperThread.js')
post.pthr = new PoolThread('init_thr_crypto.js')
post.pthr.eval('thrSendObj', [o], function thrSendObj(e){
var ar = [].slice.call(arguments)
if(ar.length !== 2) return post.log('e', 'ожидаются два аргумента: '+JSON.stringify(ar))
var fn = arguments.callee.name; post.log('e', new Date().toHex() + ': '+fn+' ' + jsext.stringify(ar))
})
post.pthr.eval('thrGetObj', [], function thrGetObj(e){
var ar = [].slice.call(arguments)
if(ar.length !== 2) return post.log('e', 'ожидаются два аргумента: '+JSON.stringify(ar))
var fn = arguments.callee.name; post.log('e', new Date().toHex() + ': '+fn+' ' + jsext.stringify(ar))
})
// Будет создано два потока, один из которых будет автоматически удален,
// если в течение 2 минут не будет загружен задачами