1. はじめに
matlab マルチスレッド、parfor ループの進行状況、matlab mutex
2. ソフトウェア環境
2.1 マットラボ 2022b
2.2 コードリンク
https://gitee.com/JJW_1601897441/csdn
3. 主な工程
3.1 MATLAB マルチスレッド化
いくつかのタイプがあります。最も単純で最もよく理解されているのは parfor です。これを例に挙げます。使用方法は、各 for ループが相互に依存できないことです。計算の各ラウンドは独立しているため、parfor を使用できます。バージョンが異なると異なります。 、古いバージョンにはさらに制限があるようです
parfor i = 1:1000
disp(i);
end
3.2 parfor サイクルの進捗状況
parfor を使用して何かを並列計算する場合、何度もループする必要があるものもありますが、プログラムが何回実行されたかわかりません。進行状況が確認できる場合、時間が長すぎるため、カウントしない可能性があります。
3.2.1 プログレスバーウィンドウモード
これは公式ドキュメントに記載されているので、使用することも、直接コピーすることもできます。
w = waitbar(0,'Please wait ...');
% Create DataQueue and listener
D = parallel.pool.DataQueue;
afterEach(D,@parforWaitbar);
N = 10000;
parforWaitbar(w,N)
parfor i = 1:N
% pause替换乘自己的就可以了
pause(rand)
send(D,[]);
end
delete(w);
function parforWaitbar(waitbarHandle,iterations)
persistent count h N
if nargin == 2
% Initialize
count = 0;
h = waitbarHandle;
N = iterations;
else
% Update the waitbar
% Check whether the handle is a reference to a deleted object
if isvalid(h)
count = count + 1;
waitbar(count / N,h);
end
end
end
3.2.2 下部のプログレスバーの表示方法
使い方を知ってください。公式 Web サイトにもあります。これには、同じレベルのディレクトリに配置できるファイルも必要です。コードをリンクに置きます。
% 设置循环次数
N = 10000;
% 创建一个迭代计数器对象
parfor_progress(N);
parfor i = 1:N
% pause替换乘自己的就可以了
pause(rand)
parfor_progress;
end
parfor_progress(0);
3.3 MATLAB ミューテックス
parforサイクルではデータの読み書きが非常に面倒です 並列計算は結果を計算することですが、parforでの計算結果を受け取るのが大変です 回数が多いと配列を受け取るのは現実的ではありません各サイクルでデータをファイルに書き込むと、parfor はエラーを報告します。たとえそれが可能だったとしても、MATLAB にはミューテックスがないため、ファイルを書き込むことができたとしても、それはカオスになります。
同じ文です。使い方がわかったらそのまま使ってください。自分の文章に置き換えるだけです。コメントはその中に書かれています。
% 创建一个 DataQueue 对象
dq = parallel.pool.DataQueue;
file = fopen('ccc.txt','w');
% 多重匿名函数
fun_with_params = @(data) saveData(data, file);
% 在 DataQueue 上设置 afterEach 方法,
% 这个是给数据绑定一个处理方法,就是在信号发送以后,执行那个处理方法,
% 这个处理方法不是并行的,同一时刻只有一个线程在处理数据,其他的线程都要排队
% 和互斥锁的思想很像
afterEach(dq, fun_with_params);
% 在工作线程中定义处理函数并发送数据到 DataQueue
parfor i = 1:100
% 替换成自己的
a = rand();
% 在这里通过 send 函数将数据发送到 DataQueue
% 可以发送单个,也可也发送数组
send(dq, a);
end
fclose(file);
function saveData(data, file)
% 在此处编写后处理代码
fprintf(file,'%.10f ', data);
fprintf(file,'\n');
end
3.4 parfor_progress.m
function percent = parfor_progress(N)
%PARFOR_PROGRESS Progress monitor (progress bar) that works with parfor.
% PARFOR_PROGRESS works by creating a file called parfor_progress.txt in
% your working directory, and then keeping track of the parfor loop's
% progress within that file. This workaround is necessary because parfor
% workers cannot communicate with one another so there is no simple way
% to know which iterations have finished and which haven't.
%
% PARFOR_PROGRESS(N) initializes the progress monitor for a set of N
% upcoming calculations.
%
% PARFOR_PROGRESS updates the progress inside your parfor loop and
% displays an updated progress bar.
%
% PARFOR_PROGRESS(0) deletes parfor_progress.txt and finalizes progress
% bar.
%
% To suppress output from any of these functions, just ask for a return
% variable from the function calls, like PERCENT = PARFOR_PROGRESS which
% returns the percentage of completion.
%
% Example:
%
% N = 100;
% parfor_progress(N);
% parfor i=1:N
% pause(rand); % Replace with real code
% parfor_progress;
% end
% parfor_progress(0);
%
% See also PARFOR.
% By Jeremy Scheff - jdscheff@gmail.com - http://www.jeremyscheff.com/
error(nargchk(0, 1, nargin, 'struct'));
if nargin < 1
N = -1;
end
percent = 0;
w = 50; % Width of progress bar
if N > 0
f = fopen('parfor_progress.txt', 'w');
if f<0
error('Do you have write permissions for %s?', pwd);
end
fprintf(f, '%d\n', N); % Save N at the top of progress.txt
fclose(f);
if nargout == 0
disp([' 0%[>', repmat(' ', 1, w), ']']);
end
elseif N == 0
delete('parfor_progress.txt');
percent = 100;
if nargout == 0
disp([repmat(char(8), 1, (w+9)), char(10), '100%[', repmat('=', 1, w+1), ']']);
end
else
if ~exist('parfor_progress.txt', 'file')
error('parfor_progress.txt not found. Run PARFOR_PROGRESS(N) before PARFOR_PROGRESS to initialize parfor_progress.txt.');
end
f = fopen('parfor_progress.txt', 'a');
fprintf(f, '1\n');
fclose(f);
f = fopen('parfor_progress.txt', 'r');
progress = fscanf(f, '%d');
fclose(f);
percent = (length(progress)-1)/progress(1)*100;
if nargout == 0
perc = sprintf('%3.0f%%', percent); % 4 characters wide, percentage
disp([repmat(char(8), 1, (w+9)), char(10), perc, '[', repmat('=', 1, round(percent*w/100)), '>', repmat(' ', 1, w - round(percent*w/100)), ']']);
end
end
3.5 補足
次のコードに従って実行されます。afterEach は、データが渡された後に対応する関数が実行されることを保証するだけであり、ループ内のすべての関数が一緒に実行されることを意味するわけではありません。
% 创建一个 DataQueue 对象
dq1 = parallel.pool.DataQueue;
dq2 = parallel.pool.DataQueue;
file1 = fopen('ccc1.txt','w');
file2 = fopen('ccc2.txt','w');
% 多重匿名函数
fun_with_params1 = @(data) saveData(data, file1);
fun_with_params2 = @(data) saveData(data, file2);
% 在 DataQueue 上设置 afterEach 方法
afterEach(dq1, fun_with_params1);
afterEach(dq2, fun_with_params2);
% 在工作线程中定义处理函数并发送数据到 DataQueue
parfor i = 1:1000
% 替换成自己的
a = rand();
% 在这里通过 send 函数将数据发送到 DataQueue
% 可以发送单个,也可也发送数组
send(dq1, a);
send(dq2, a);
end
% 等待所有数据接收完成
% 显示接收到的数据
% 辅助函数用于保存接收到的数据到数组
function saveData(data, file)
% 在此处编写后处理代码
fprintf(file,'%.10f ', data);
fprintf(file,'\n');
end
向上
% 创建一个 DataQueue 对象
dq1 = parallel.pool.DataQueue;
file1 = fopen('ccc11.txt','w');
file2 = fopen('ccc21.txt','w');
file3 = fopen('ccc31.txt','w');
% 多重匿名函数
fun_with_params1 = @(data1) saveData(data1, file1, file2,file3);
% 在 DataQueue 上设置 afterEach 方法
afterEach(dq1, fun_with_params1);
% 在工作线程中定义处理函数并发送数据到 DataQueue
parfor i = 1:100
% 替换成自己的
a = rand();
data = {
i,i,i}
% 在这里通过 send 函数将数据发送到 DataQueue
% 可以发送单个,也可也发送数组
send(dq1, data);
end
% 等待所有数据接收完成
fclose(file1);
fclose(file2);
fclose(file3);
% 显示接收到的数据
% 辅助函数用于保存接收到的数据到数组
function saveData(data, file1,file2,file3)
% 在此处编写后处理代码
data1 = data{
1};
data2 = data{
2};
data3 = data{
1};
fprintf(file1,'%.10f ', data1);
fprintf(file1,'\n');
fprintf(file2,'%.10f ', data2);
fprintf(file2,'\n');
fprintf(file3,'%.10f ', data3);
fprintf(file3,'\n');
end