суббота, 12 декабря 2015 г.

Freemat. Многопоточность

Вам грустно? Одиноко? Устали ждать, когда закончится расчёт? Попробуйте многопоточность!:) 


Рассмотрим это на примере двух скриптов. Первый вариант выполняет расчёт в основном потоке.

       test1.m
a = rand(100,100);  % массив случайных числе 100х100
tic;                           % засекаем начало
a^100;                     % возводим массив в степень 100
toc                           % засекаем окончание

Второй вариант создаёт 2 дополнительных потока и распределяет вычисления между ними.
      test2.m
a = rand(100,100);  % массив случайных числе 100х100
h1 = threadnew;      % первый поток
h2 = threadnew;      % второй поток

tic;                            % засекаем начало
threadstart(h1, 'power', 1, a, 50); % вычисляем a^50 в одном потоке
threadstart(h2, 'power', 1, a, 50); % вычисляем a^50 во втором потоке
res1 = threadvalue(h1);                % результат для 1-го потока
res2 = threadvalue(h2);                % результат для 2-го потока
res1*res2;                % значение для сотой степени
threadfree(h1);        % освобождаем 1-й поток
threadfree(h2);        % освобождаем 2-й поток
tok                           % засекаем окончание

Теперь можно в FreeMat ввести "test1", и после нажатия Enter программа сообщит о длительности расчёта. В моём случае это 0,394 c. Затем аналогично вводим "test2". Время расчёта у меня составило 0,012 с. На самом деле во втором случае задействованы 3 потока: 2 дополнительных и 1 основной, который мы практически не использовали. Можно было бы создать один дополнительный поток и распределить вычисления между ним и основным потоком, но мои эксперименты показали, что при этом время понижается незначительно, видимо, он и без того нагружен. Отсюда можно сделать вывод, что для большого расчёта имеет смысл выделять отдельный поток.  

Теперь рассмотрим, что необходимо для работы с многопоточностью в FreeMat. Новый поток создаётся функцией threadnew, которая возвращает его идентификатор. Дальнейшая работа с потоком осуществляется на основе этого идентификатора. Запуск расчёта выполняет функция 
threadstart(поток, функция, результат, аргумент1, аргумент2, ...).
Здесь поток означает идентификатор, функция - имя функции (в кавычках), обрабатываемой в данном потоке, результат - число ожидаемых возвращаемых значений для функции (видимо, для каких-то специфических случаев). Далее идёт список аргументов, передаваемых выполняемой функции. В поток нельзя передать имя скрипта, это должна быть именно функция, встроенная или написанная пользователем. Все значения вычисляются локально, если необходима возможность обмена данными между потоками, соответствующие переменные должны быть объявлены с ключевым словом global, т.е. глобальными. В этом случае программа сама позаботится о том, чтобы исключить проблемы, связанные с совместным использованием данных несколькими потоками. 
[рез1, рез2, ...] = threadval(поток, время ожидания)
считывает результат вычислений из потока с заданным идентификатором по окончании его работы. Если есть подозрение, что расчёт может уйти в бесконечный цикл, можно поставить максимальное время ожидания (в миллисекундах), при превышении которого будет возвращена ошибка. 

По окончании работы с потоком его нужно освободить. Для этого служит функция threadfree(поток).

В FreeMat предусмотрено ещё несколько функций для работы с потоками. Однако рассмотренных выше для начала будет вполне достаточно.

Комментариев нет:

Отправить комментарий