병렬 할당을 사용한 멀티스레딩 문제 해결나는 행 단위 작업에서 큰 데이터 테이블(>8MM)에서 작동하도록 멀티스레딩을 시도하는 Mac 시스템에 있습니다. 나누기나 값을 그대로 복사하는 등의 단순한 계산일 뿐입니다. 내 독점 데이터를 첨부할 수는 없지만 이 게시물에서는 내 데이터 세트와 크기는 같지만 임의 데이터가 포함된 임의 행렬을 JSL에 포함할 것입니다.
Names Default To Here(1);<BR /><BR />//For JMP community.
dt = J(Random Integer(6000000 , 8000000) , 5 , Random Integer(10)); <BR />dt = As Table(dt); <BR /><BR />//dt = Current Data Table(); //Table needs to be formatted such that data table has 5 columns with names X , Y , Z , Filename , Radius.
//columns must be in that order for matrix functionality to work
edgeExclusion = 0.01; //in units of radial meters
stepSize = 0.0025; //in meters; this is the resolution of the desired particle size analysis. This is the side length of the square of the defect area resolution desired.
waferSize = 0.2; //in meters, diameter
If( Floor( waferSize / stepSize ) != Ceiling( waferSize / stepSize ) , Throw( "!Defect resolution size not a common factor of wafer size"));
//Takes data table as matrix (fDT) and returns matrix of x, y, stddev, stddev points, and UID.
//Requires datatable to have X , Y , Z , Filename , Radius , and UID so that matrix fDT has X , Y , Z , Radius , and UID; in that order.
stdDevCalculator2 = Function ( { fDT , fFirstRow , fLastRow , fWS , fEE , fSS } , {Default Local} ,
fSubDT = fDT[ fFirstRow :: fLastRow , 0];
outputMat = J(0,5);
For( i = 1 , i <= N Rows(fSubDT) , i++ ,
//If( fSubDT[i,4] > (fWS/2)-fEE , Continue()); //Possibly remove to keep number of columns same for Parallel Assign
rowMat = Matrix( { Floor(fSubDT[i,1]/fSS) , Floor(fSubDT[i,2]/fSS) , fSubDT[i,3] , fSubDT[i,4] , fSubDT[i,5] } );
rowMat = Shape(rowMat,1,5);
If(N Rows(outputMat) == 0 , outputMat = rowMat , Concat To(outputMat , rowMat));
);
outputMat[1,0];
);
t1 = Tick Seconds();
numThreads = 8;
//Number of rows to delete to make Parallel Assign function operate. Trimming original data table to even multiple of thread count will allow tOutMat to be a square matrix,
//so that each thread is assigning the same number of columns.
delNum = N Rows(dt) - (Floor(N Rows(dt)/numThreads)*numThreads);
dt << Select Randomly(delNum);
dt << Delete Rows(); //Trim data set
numCols = 5 * (N Rows(dt)/numThreads); //5 for number of colums in original stacked data table.
//outMat = stdDevCalculator2(dtMat , 1 , N Rows(dtMat) , waferSize , edgeExclusion , stepSize); //For single threaded testing
dtMat = dt << GetAsMatrix;
tOutMat = J(numThreads,numCols);
Parallel Assign(
{tDT = dtMat, tWS = waferSize, tEE = edgeExclusion, tSS = stepSize, tSDC = Name Expr(stdDevCalculator2), tNum = numThreads },
tOutMat[i,0] = tSDC( tDT, 1 + Floor((i - 1) * N Rows(tDT) / tNum) , Floor( i * N Rows(tDT) / tNum) , tWS, tEE, tSS );
);
Show(tOutMat);
Write( "elapsed time=", Tick Seconds() - t1 );내 문제는 이 스크립트가 실행될 때 내 모든 핵심 사용률이 100%로 점프하기 때문에 내 Mac 시스템에서 Parallel Assign이 작동하는 것처럼 보입니다. 그러나 종료할 충분한 시간을 준 후(단일 스레드 버전이 끝난 후) 강제로 종료해야 합니다.
JSL이 다른 행렬에 값의 행 단위 집합을 "주입"하는 것을 선호하는 방법을 이해하기 위해 몇 가지 작업을 수행했습니다. 아래 예를 들어보세요.
Names Default to Here(1);
mat1 = J(3,5,0);
mat2 = J(1,5,Random Integer(5));
show(mat1);
Show(mat2);
mat1[2,0] = mat2[1,0];
Show(mat1);
mat1은 이제 두 번째 행에 mat2의 완전한 복사본을 갖게 됩니다. N 행(테이블)/N 스레드가 있는 단일 행을 반환하여 이와 동일한 종류의 행렬 할당을 에뮬레이트하려고 했습니다. 왜 내가 이것을 작동시킬 수 없는지에 대해 생각하는 사람이 있습니까?
Re: Parallel Assign을 사용한 멀티스레딩 문제 해결느린 JSL에 대한 재수사: tDT 값은 거대한 복사되는 행렬 거대한 tf 함수에 전달할 횟수입니다.8E6 * 8E6 숫자가 복사됩니다. 스레드가 메모리 액세스를 기다리고 있습니다.
tOutMat[i,j] = tf( tDT, i , j , tSS )
해당 복사는 빠른 JSL에서 발생하지 않습니다.
Re: Parallel Assign을 사용한 멀티스레딩 문제 해결안녕 @msulzer_bsi
몇 가지 일반적인 설명: 멀티스레딩은 해결하려는 문제가 병렬화할 수 없거나 계산하려는 문제가 너무 작아 단일 스레드에서 컴퓨팅하는 것보다 스레드 생성에 더 많은 시간이 소요될 때 나쁜 생각입니다.
문제를 병렬로 실행할 수 있는 부분으로 나눌 수 있는 경우 그렇게 하는 것이 좋을 수 있지만 병렬로 실행할 수 있는 부분과 하위 문제 결과를 결합하는 것이 얼마나 쉬운지에 따라 다릅니다. 알고리즘이 새 스레드에서 새로운 하위 문제로 분해하기 위해 여러 조인(하나의 스레드에 대한)이 필요한 경우 병렬화하는 데 노력할 가치가 있으려면 매우 계산 집약적이어야 합니다. 하위 문제 결과 목록을 한 번 결합하면 잠재력이 있습니다.
나는 당신의 작업에서 많은 이점을 보지 못하고 2초에 걸쳐 얻을 수 있는 속도 향상은 그리 많지 않을 수 있습니다. 그래서 다른 스레드에서 실행될 수 있거나 실행되었을 수 있는 htis 다른 작업으로 이러한 노력을 기울이고 차단하려는 이유는 무엇입니까? 때때로 당신이 해야 할 일에 대해 0.5초를 더 얻을 가치가 없습니다. 2-3개의 다른 데이터 청크를 모두 처리하는 높은 처리량 애플리케이션이 아닌 한, 말씀하신 것처럼 >8MM의 데이터로 인해 이 작업을 고정할 타당한 이유가 없습니다.
Re: Parallel Assign을 사용한 멀티스레딩 문제 해결안녕 @Craige_Hales ,
병렬 할당 내에서 함수 정의를 생성하라는 조언을 활용했습니다. 아래를 참조하십시오.
Names Default To Here(1);
dt = Current Data Table(); //Table needs to be formatted such that data table has 5 columns with names X , Y , Z , Filename , Radius.
//columns must be in that order for matrix functionality to work
edgeExclusion = 0.01; //in units of radial meters
stepSize = 0.0025; //in meters; this is the resolution of the desired particle size analysis. This is the side length of the square of the defect area resolution desired.
waferSize = 0.2; //in meters, diameter
If( Floor( waferSize / stepSize ) != Ceiling( waferSize / stepSize ) , Throw( "!Defect resolution size not a common factor of wafer size"));
t1 = Tick Seconds();
numThreads = 8;
//Number of rows to delete to make Parallel Assign function operate. Trimming original data table to even multiple of thread count will allow tOutMat to be a square matrix,
//so that each thread is assigning the same number of columns.
delNum = N Rows(dt) - (Floor(N Rows(dt)/numThreads)*numThreads);
If( delNum != 0 , dt << Select Randomly(delNum));
dt << Delete Rows(); //Trim data set
dtMat = dt << GetAsMatrix;
dtMat = Shape(dtMat , numThreads);
tOutMat = J(numThreads , N Cols(dtMat));
Parallel Assign(
{tDT = dtMat, tSS = stepSize, tf = Function ( { fDT , x , y , fSS } ,
If( Mod(y,5) == 1 , Floor(fDT[x,y]/fSS) ,
Mod(y,5) == 2 , Floor(fDT[x,y]/fSS) ,
fDT[x,y];
);
); },
tOutMat[i,j] = tf( tDT, i , j , tSS );
);
Show(tOutMat);
Write( "elapsed time=", Tick Seconds() - t1 );이제 스크립트를 실행하고 이상한 출력을 제공하거나 오류를 발생시키지 않습니다. 출력 행렬의 각 조합을 평가하기 위해 병렬 할당을 사용하는 것에 대해 설명한 내용을 재평가했습니다. 출력 행렬의 위치 함수로.필자의 경우 원래 행이 긴 데이터 테이블의 처음 두 열에 있는 값(따라서 Mod() ==1 및 Mod() ==2 문)에 대한 계산 수행에만 관심이 있습니다. 이것은 엄격한 테이블 형식 입력 요구 사항 때문에 가장 유연한 스크립트는 아니지만 나중에 문제가 됩니다.
그러나 이제는 멀티스레드 버전의 스크립트를 실행할 때 실행 시간이 200초까지 걸리는 이상한 현상이 발생합니다. 단일 스레드 스크립트로 아래와 같이 중첩된 for 루프가 되도록 병렬 할당 문을 다시 작성할 때:
For(i = 1 , i <= numThreads , i++ ,
For(j = 1 , j <= numCols , j++ ,
If( Mod(j,5) == 1 , tOutMat[i,j] = Floor(dtMat[i,j]/stepSize) ,
Mod(j,5) == 2 , tOutMat[i,j] = Floor(dtMat[i,j]/stepSize) ,
tOutMat[i,j] = dtMat[i,j];
);
);
);
실행 시간 ~2초를 얻을 수 있습니다... 단일 스레드 작업과 다중 스레드 작업의 프로세스를 보다 균등하게 비교할 수 있도록 불필요하지만 입력 행렬을 형성했습니다. 다중 스레드 버전이 훨씬 느려지는 원인이 되는 오버헤드가 어떤 종류인지 이해할 수 없습니다. 내 질문을 처음 게시했을 때부터 행렬 계산을 상당히 줄였습니다. 통찰력이 있습니까?
감사합니다, msulzer
Re: Parallel Assign을 사용한 멀티스레딩 문제 해결안녕 크레이지,
제 질문에 답변해 주셔서 감사합니다. 나는 Parallel Assign에 대한 나의 학습이 주로 당신이 이전에 게시한 몇 가지 예에 기인하기 때문에 적어도 당신이 스레드를 볼 수 있기를 바랐습니다. 귀하의 진술의 핵심 의미가 무엇인지 이해하고 제 특정 사례에 적용할 수 있는 결과를 알려드리겠습니다.
Re: Parallel Assign을 사용한 멀티스레딩 문제 해결Parallel Assign이 할 수 없는 일을 기대하고 있다고 생각합니다. 이 코드
tOutMat[i,0] =
Parallel Assign에서 저를 놀라게 했습니다. Parallel Assign이 기대하는 유일한 것은 0이 아니라 해당 첨자에 대한 JSL 변수 이름입니다. 0은 조용히 무시되고 할당의 오른쪽은 두 번째 인덱스가 무엇인지 알 방법이 없는 것으로 보입니다.다음은 몇 가지 예입니다. 두 번째 첨자를 0으로 변경하면 무시되는 것을 볼 수 있습니다.
하나. 각 스레드에 로컬인 변수 i를 사용하고 사용할 때마다 증가시킵니다. j,k(또는 j,0) 인덱스 값은 요소에 대해 계산된 값을 결정하는 데 사용되지 않습니다.
x = J( 7, 11 );
Parallel Assign( {i = 0}, x[j, k] = (i++) );
Show( x );엑스 =
[ 0 0 0 0 1 1 1 2 2 2,
2 3 3 3 3 4 4 4 4 5 5,
5 5 6 6 6 6 7 7 7 7 8,
8 8 8 9 9 9 9 10 10 10 10,
11 11 11 11 12 12 12 12 13 13 13,
13 14 14 14 14 15 15 15 15 16 16,
16 16 17 17 17 17 18 18 18 18 19];
둘. 비슷한, 같은 것을 다른 방식으로 보여줍니다. 스레드는 각각 변경되지 않은 고유한 값을 얻습니다. h=4는 사용 가능한 프로세서 수를 암시합니다. 표시된 것처럼 항상 계산을 인터리빙하는 JMP에 의존해서는 안 되지만 지금은 그렇게 되어 있습니다.
x = J( 7, 11 );
h = 0;
Parallel Assign( {i = (h++)}, x[j, k] = i );
Show( x, h );엑스 =
[ 0 1 2 3 0 1 2 3 0 1 2,
3 0 1 2 3 0 1 2 3 0 1,
2 3 0 1 2 3 0 1 2 3 0,
1 2 3 0 1 2 3 0 1 2 3,
0 1 2 3 0 1 2 3 0 1 2,
3 0 1 2 3 0 1 2 3 0 1,
2 3 0 1 2 3 0 1 2 3 0];
h = 4;
삼. 단일 전역 변수를 사용하십시오. 사용할 때마다 증가합니다. 스레드는 서로를 잠그고 특정 순서로 실행되거나 실행되지 않을 수 있습니다.
x = J( 7, 11 );
global:g = 0;
Parallel Assign( {i = (h++)}, x[j, k] = (global:g++) );
Show( x, g );엑스 =
[ 0 20 39 58 1 21 40 59 2 22 41,
60 3 23 42 61 4 24 43 62 5 25,
44 63 6 26 45 64 7 27 46 65 8,
28 47 66 9 29 48 67 10 30 49 68,
11 31 50 69 12 32 51 70 13 33 52,
71 14 34 53 72 15 35 54 73 16 36,
55 74 17 37 56 75 18 38 57 76 19];
g = 77;
위의 모든 경우에서 k를 0으로 바꾸면 아무 것도 변경되지 않습니다. 내부적으로 병렬 할당은 여전히 모든 인덱스 쌍을 계산하고 스레드 중 하나에 각 쌍의 값을 계산하도록 요청합니다.
이 경로를 계속 탐색하는 경우 다음과 같이 각 스레드에 대해 별도의 함수 인스턴스를 만드는 것이 좋습니다.
x = J( 2, 3 );
Parallel Assign( {f = Function( {x, y}, x * y )}, x[i, j] = f( i, j ) );
Show( x );x = [1 2 3, 2 4 6];
이로 인해 각 스레드의 로컬 f가 별도의 JSL 함수 사본을 갖게 됩니다. nameexpr은 별도의 사본을 만들지 않으며 필요 올바르게 병렬로 실행하려면 분리해야 합니다.
전역 배열 요소에 할당을 사용할 수도 있습니다. 올바른 길이의 1차원 배열을 사용하여 병렬 할당을 구동합니다.
global:results = J( 5, 7, . );
driver = J( N Rows( results ), 1, 0 );
h = 0;
Parallel Assign(
{procNum = (1 + h++), NC = N Cols( results )},
driver[j] =
(
For( k = 1, k <= NC, k += 1,
global:results[j, k] = procNum * 100 + j * 10 + k
);
procNum// value assigned to driver
)
);
Show( global:results, h, driver );글로벌:결과 =
[ 111 112 113 114 115 116 117,
221 222 223 224 225 226 227,
331 332 333 334 335 336 337,
441 442 443 444 445 446 447,
151 152 153 154 155 156 157];
h = 4;
드라이버 = [1, 2, 3, 4, 1];
그러나 전역 변수는 아마도 단일 스레드만큼 느리게 실행될 것입니다.
마지막으로 Parallel Assign은 두 개의 스레드가 일부 내부 구조에 동시에 액세스하여 잘못된 결과를 생성하거나 충돌을 일으킬 수 있는 안전하지 않은 코드를 작성하지 않도록 합니다. Parallel Assign의 방어를 피할 수 있는 JSL을 작성할 수 있습니다. 봉투를 밀고 있다면 작업을 자주 저장하십시오.