컴퓨팅이 발전하면서 내 워크스테이션의 코어는 1개에서 2개, 4개, 64개로 늘어났습니다. 한편 .jsl은 사실상 단일 스레드로 유지되었습니다. 일부 플랫폼은 모든 스레드를 활용한다는 것을 알고 있지만 마음대로 간단한 jsl 작업을 여러 스레드로 처리할 수 있기를 바랍니다. 예를 들어, 10,000,000개의 데이터 행에 대해 행 단위로 작동하는 스크립트가 있고 for 루프에서 행별로 반복하고 각 행의 결과가 다른 행과 독립적이라는 것을 알고 있다면 이를 분할하고 싶습니다. 64개의 비동기 for 루프로 작업을 수행하고, 64개의 루프가 병렬로 완료되는 동안 다른 실행을 일시 중지한 다음, Pool() 및 poolObject.join을 사용하여 .py에서 하는 것처럼 모든 작업이 완료된 후 단일 스레드 동기 스크립트로 다시 이동합니다.
안녕 스티브,
JMP에는 압축된 데이터 테이블 저장/열기(각 열이 다른 스레드로 전송됨)부터 여러 열이 있는 배포 플랫폼(각 분포 분석은 다른 스레드), Mersenne-Twister 무작위 균일 생성기. 보시다시피 멀티스레딩은 다양한 곳에서 수행됩니다.
그래서, 우리는 실제로 그런 목록을 가지고 있지 않습니다. 여기서 질문을 유도하는 것은 무엇입니까?
안녕 제프,
멀티스레딩을 활용하는 플랫폼/내장 작업은 어디에서 찾을 수 있나요?
위에서 직접 언급했듯이 이는 JSL에서 수행할 작업의 범위를 벗어나는 것입니다. 멀티스레딩을 통해 이점을 얻을 수 있다고 생각되는 특정 작업이 있는 경우 세부 사항과 함께 다른 희망사항을 열어주세요.
이 희망 사항에는 많은 표가 있지만 불행히도 Parallel Assign()에서 제공하는 것 이상의 것은 전달하기 어려울 것입니다. 사용자 인터페이스와의 긴밀한 통합과 JMP의 대화형 특성으로 인해 가능한 JSL을 기본적으로 Parallel Assign이 허용하는 수준으로 제한하지 않고 스레드로부터 안전한 환경을 제공하는 것은 불가능합니다.
멀티스레딩을 활용하는 가장 좋은 방법은 내장된 플랫폼을 최대한 많이 사용하는 것입니다. 이러한 플랫폼에서는 멀티스레드 솔루션을 직접 제공할 수 있습니다.멀티스레딩이 유용할 것이라고 생각하는 내장 작업에 대한 다른 희망 사항을 여는 것이 더 많은 멀티스레딩을 보고 싶은 부분을 알려주는 가장 좋은 방법입니다.
간단한 JSL 작업을 여러 스레드로 처리하는 경우 이를 위한 Parallel Assign()이라는 함수가 있습니다. 작업을 청크로 나누고 각 청크에 대한 코드는 단일 숫자가 되며 전체 작업의 결과는 다음과 같습니다. 숫자의 행렬.
Parallel Assign()에 대한 스크립팅 인덱스에는 장난감 예제가 있으며, Frame Size()에 대한 두 번째 예제는 Mandelbrot 세트 데이터를 계산하기 위한 보다 정교한 예제를 보여줍니다. 또 다른 작은 예는 @Craige_Hales '에스 루프에 대한 JSL Cookbook 게시물 그리고 거기에 만델봇에 대해 더 알아보기 그의 블로그에서.
멀티스레딩을 사용하여 파일 목록에서 가장 큰 파일을 찾는 또 다른 예가 아래에 포함되어 있습니다. 스크립트는 먼저 단일 스레드 버전을 실행하며 이 작업 관리자 스크린샷에서 두 가지 활동을 모두 볼 수 있습니다. 단일 스레드 버전은 긴 메사이고 병렬 버전은 높은 피크입니다. 8개 코어에 있는 17,000개 파일의 경우 시간이 13초에서 4.5초로, 즉 3배 더 빨라졌습니다. 이상적이지는 않지만 흔히 그렇듯이 스레드는 이 경우 디스크 액세스와 같은 일부 리소스를 공유합니다.
병렬로 실행되는 JSL은 공유 전역 상태를 수정하지 않도록 단순해야 합니다. 이것이 첫 번째 단계로 일부 전역 변수가 복사되는 이유입니다. 이는 또한 병렬 코드가 데이터 테이블을 생성하거나 디스플레이와 상호 작용하는 등의 작업을 수행할 수 없음을 의미합니다.
우리는 더 풍부한 인터페이스가 필요할 수 있는 다른 간단한 작업이 무엇인지 알고 싶습니다. 내가 아는 것 중 하나는 각 작업자가 숫자가 다른 항목을 반환하는 것입니다. 본질적으로 이는 행렬 대신 결과 목록을 사용하는 것을 의미합니다.
----
Names Default To Here( 1 );
// Example for Parallel Assign().
// get a list of a lot of files
dir = If(Host is("Mac"), "$SAMPLE_DATA", "$JMP_HOME");
all files = Files In Directory( dir, "recursive" );
naf = N Items( all files );
// convert relative paths to full paths
For( i = 1, i <= naf, i++,
all files[i] = dir || "/" || all files[i]
);
// Function that looks at a range of a given file list and returns
// the index of the largest file.
// Importantly, this function uses no global variables.
largest file = Function( {files, first, last},
{i, i large = -1, bytes large = -1, bytes},
For( i = first, i <= last, i++,
bytes = File Size( files[i] );
If( bytes > bytes large,
bytes large = bytes;
i large = i;
);
);
i large;
);
// Single-threaded approach: see all the files to the function.
t0 = Tick Seconds();
lf = largest file( all files, 1, naf );
t1 = Tick Seconds();
Show( naf, lf, all files[lf], t1 - t0 );
// about 13sec on my machine (17k files on Win)
wait(1); // so we can see a break in a CPU activity monitor
// Multi-threaded approach: break the list up into 8 ranges that
// can be handled by separate threads.
t0 = Tick Seconds();
num chunks = 8; // JMP may create this many threads, or fewer
// initialize to -1, so we can detect failure if desired
results = J( num chunks, 1, -1 );
Parallel Assign(
// copy these globals into the thread's local variables
{tf = Name Expr( largest file ), tfiles = all files, tn = num chunks},
// make this assignment for each chunk:
results[i] = Local( {n = N Items( tfiles )},
tf( tfiles, 1 + Floor( (i - 1) * n / tn ), Floor( i * n / tn ) )
)
);
// We need to call the function once more to see which of the top
// files is the overall largest.
top files = all files[results];
toplf = largest file( top files, 1, num chunks );
lf = results[toplf];
t1 = Tick Seconds();
Show( naf, lf, all files[lf], t1 - t0 );
// about 4.5sec