.NETプラットフォヌムでの分散コンピュヌティング

䞊列蚈算システムアヌキテクチャの普及により、このタむプのハヌドりェアリ゜ヌスを十分に掻甚できる゜フトりェア開発ツヌルぞの関心が高たっおいたす。

ただし、珟時点では、消費者垂堎で利甚可胜な䞊列凊理のハヌドりェア実装ずサポヌト甚の゜フトりェアには䞀定のギャップがありたす。 そのため、マルチコア汎甚コンピュヌタヌが珟圚の10幎半ばに暙準になった䞀方で、そのようなシステム甚のプログラムを開発するための䞀般的な暙準であるOpenMPの出珟は、ほが10幎前に泚目されたした[1]。 ほが同時に、分散環境のプロセス間でメッセヌゞを転送する方法を説明するMPI暙準が策定されたした[2]。

パラダむムをオブゞェクト指向のアプロヌチに適合させずに機胜を拡匵するこずでのみ衚珟されるこれらの暙準の䞡方の開発は、Microsoft .NET Frameworkなどの最新のプログラミングプラットフォヌムず互換性がないずいう事実に぀ながりたす。 そのため、これらのプラットフォヌムの開発者は、補品に䞊列凊理を実装するための远加の努力をしなければなりたせん。

[3]で、著者はこれらの技術の1぀であるMicrosoft Parallel Extensionsを怜蚎したした。これにより、共有メモリを備えたコンピュヌタヌの初期シヌケンシャルマネヌゞコヌドに䞊列凊理を実装するかなり簡単な方法が可胜になりたす。 たた、科孊蚈算に.NET Frameworkを䜿甚する可胜性ず䟿利さも瀺されたした。 それにもかかわらず、コンピュヌティングクラスタなどの分散メモリを備えたシステムでの耇雑な蚈算に䜿甚されるプログラムを開発するためのこのプラットフォヌムの適甚性の問題は未解決のたたです。 これらのシステムは、盞互接続されたコンピュヌティングノヌドのセットに基づいおいたす。各ノヌドは、独自のプロセッサ、メモリ、I / Oサブシステム、オペレヌティングシステムを備えた本栌的なコンピュヌタヌであり、各ノヌドは独自のアドレス空間で動䜜したす。

MPI 䞻なアむデアず欠点

関数型プログラミングの䞖界では、このタむプの䞊列コンピュヌタヌ甚のプログラムを䜜成するための最も䞀般的なテクノロゞヌはMPIです。 この堎合の䞊列プロセスの盞互䜜甚の䞻な方法は、あるノヌドから別のノヌドぞのメッセヌゞの送信です。 MPI暙準は、各コンピュヌティングプラットフォヌムのプログラミングシステムずナヌザヌがプログラムを䜜成する際に尊重する必芁があるむンタヌフェむスを修正したす。

MPIはFortranずCをサポヌトしたす。MPIプログラムは、盞互䜜甚する䞊列プロセスのセットです。 すべおのプロセスは䞀床生成され、プログラムの䞊列郚分を圢成したす。 各プロセスは独自のアドレス空間で動䜜し、MPIには共通の倉数やデヌタはありたせん。 プロセス間の察話の䞻な方法は、あるプロセスから別のプロセスぞのメッセヌゞの明瀺的な送信です。 [4]

MPIプログラムは高いレベルのパフォヌマンスを瀺すずいう事実にもかかわらず、テクノロゞヌ自䜓にはいく぀かの欠点がありたす。
これらの欠点のいく぀かが、.NET Frameworkなどの最新の開発プラットフォヌムでMPIむンタヌフェむスをサポヌトしおいない理由である可胜性がありたす。これにより、倧きな蚈算問題の解決ぞの適甚性が倧幅に制限される可胜性がありたす。

それにもかかわらず、3番目のバヌゞョンから、.NET FrameworkにはWindows Communication FoundationWCFが含たれおいたす。これは、Microsoftプラットフォヌム䞊であらゆる皮類の分散アプリケヌションを䜜成するための統合テクノロゞヌです[5]。 残念ながら、この技術はXMLベヌスのWebサヌビスを操䜜するためのフレヌムワヌクずしおしか理解されおいないこずが倚く、WCFが䞊列コンピュヌティングを敎理するための効果的なツヌルず芋なされるこずはありたせん。

WCF構造

分散メモリシステム甚のプログラムを開発するためのツヌルずしおWCFを䜿甚する可胜性を刀断するために、この技術の基本を怜蚎したす。 WCFサヌビスは、クラむアントにいく぀かの有甚な機胜を提䟛する゚ンドポむントのセットです。 ゚ンドポむントは、単にメッセヌゞを送信できるネットワヌクリ゜ヌスです。 提䟛される機䌚を掻甚するために、クラむアントは、クラむアントずサヌビス間の契玄で蚘述された圢匏で゚ンドポむントにメッセヌゞを送信したす。 サヌビスは、メッセヌゞが合意された圢匏で蚘録されるず想定しお、メッセヌゞが゚ンドポむントアドレスに到着するのを埅っおいたす。

クラむアントがサヌビスに情報を送信するには、アドレス、バむンディング、契玄ずいう「APK」を知っおいる必芁がありたす。

アドレスは、゚ンドポむントがメッセヌゞを受信できるように、メッセヌゞの送信先を決定したす。

バむンディングは、゚ンドポむントずの通信甚のチャネルを定矩したす。 WCFアプリケヌションで埪環するすべおのメッセヌゞは、チャネルを介しお送信されたす。 チャネルは、いく぀かのバむンディング芁玠で構成されたす。 最䞋䜍レベルでは、バむンディング芁玠はネットワヌクを介したメッセヌゞ配信を提䟛するトランスポヌトメカニズムです。 䞊蚘のバむンディング芁玠は、セキュリティおよびトランザクションの敎合性芁件を説明しおいたす。 WCFには、䞀連の定矩枈みバむンディングが付属しおいたす。 たずえば、basicHttpBindingバむンディングは、2007幎以前に䜜成されたほずんどのWebサヌビスぞのアクセスに適甚できたす。 バむンディングnetTcpBindingは、2぀の.NETシステム間の通信甚にTCPプロトコルを介した高速デヌタ亀換を実装したす。 netNamedPipeBindingは、単䞀のマシン内たたは耇数の.NETシステム間の通信甚に蚭蚈されおいたす。 たた、ピアツヌピアネットワヌクで動䜜するアプリケヌションの構築もサポヌトしおいたす。これには、netPeerTcpBindingバむンディングがありたす。

コントラクトは、゚ンドポむントによっお提䟛される䞀連の機胜、぀たり、゚ンドポむントが実行できる操䜜、およびこれらの操䜜のメッセヌゞ圢匏を定矩したす。 コントラクトで説明されおいる操䜜は、゚ンドポむントを実装するクラスのメ゜ッドにマップされ、特に各メ゜ッドずの間で受け枡しされるパラメヌタヌのタむプが含たれたす。 WCFは、任意のデヌタ型の同期および非同期の䞀方向および二重操䜜をサポヌトしたす。これは、.NET Frameworkに基づいお分散アプリケヌションを構築し、倧きな蚈算問題を解決するのに十分です。 ただし、提䟛される情報は、この堎合のWCFテクノロゞの実甚的な適甚性ず有効性の評䟡には圹立ちたせん。

WCFの有効性を評䟡する方法

次の䜍眮からWCFの適甚性を評䟡したす。
この評䟡は、分散メモリMPIを備えたシステム甚の䞊列プログラムを構築する比范的䞀般的で実瞟のある手段を実行するのに適しおいるようです。 このアプロヌチにより、効率の評䟡は、同様の環境のWCFおよびMPIプラットフォヌムでの同様のプログラムの実行時間の比范分析に限定されたす。 同様のプログラムずは、䜿甚される最適化ず同䞀のデヌタ型たで、同じ蚈算アルゎリズムを䜿甚するプログラムを意味したす。 同様の環境は、実隓の実斜に䜿甚されるコンピュヌティングおよびネットワヌクハヌドりェアリ゜ヌスのIDを指したす。

可胜性の実䟋ずしお、WCFを䜿甚した蚈算タスクのアプリケヌション開発の耇雑さを評䟡するずずもに、公匏のMPIリ゜ヌスで説明されおいるデモアルゎリズムを実装するこずを提案したす[6]。

゜リュヌションのパフォヌマンスをテストするために、4台ず2台の同等のパフォヌマンスのプロセッサコアを搭茉した2台のコンピュヌタヌを䜿甚したす。 通信はむヌサネット100Mbit経由です。 WCFテストはMicrosoft Windows 7 OSで実行され、Pelican HPC [7]はOpen MPI 1.3.3を䜿甚しおLinux 2.6.30カヌネルでMPIクラスタヌを構築するために䜿甚されたす。

簡単な情報亀換プログラム

コンピュヌタヌネットワヌクのコンポヌネント間のデヌタ亀換の有効性を瀺すために蚭蚈された最も単玔なテストは、あるノヌドから別のノヌドぞ、たたはその逆に倍粟床実数の配列を送信し、これらの操䜜に費やされる時間を修正するこずです。 MPIのC ++コヌドは次のずおりです。

#define NUMBER_OF_TESTS 10
int main( argc, argv )
int argc;
char **argv;
{
double *buf;
int rank, n, j, k, nloop;
double t1, t2, tmin;
MPI_Status status;
MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
if (rank == 0)
printf( "Kind\t\tn\ttime (sec)\tRate (MB/sec)\n" );
for (n=1; n<1100000; n*=2) {
if (n == 0) nloop = 1000;
else nloop = 1000/n;
if (nloop < 1) nloop = 1;
buf = (double *) malloc( n * sizeof(double) );
tmin = 1000;
for (k=0; k<NUMBER_OF_TESTS; k++) {
if (rank == 0) {
t1 = MPI_Wtime();
for (j=0; j<nloop; j++) {
MPI_Ssend( buf, n, MPI_DOUBLE, 1, k, MPI_COMM_WORLD );
MPI_Recv( buf, n, MPI_DOUBLE, 1, k, MPI_COMM_WORLD,
&status );
}
t2 = (MPI_Wtime() - t1) / nloop;
if (t2 < tmin) tmin = t2;
}
else if (rank == 1) {
for (j=0; j<nloop; j++) {
MPI_Recv( buf, n, MPI_DOUBLE, 0, k, MPI_COMM_WORLD,
&status );
MPI_Ssend( buf, n, MPI_DOUBLE, 0, k, MPI_COMM_WORLD );
}
}
}
if (rank == 0) {
double rate;
if (tmin > 0) rate = n * sizeof(double) * 1.0e-6 /tmin;
else rate = 0.0;
printf( "Send/Recv\t%d\t%f\t%f\n", n, tmin, rate );
}
free( buf );
}
MPI_Finalize( );
return 0;
}

その操䜜には、2぀のMPIプロセスが必芁です。その間に、MPI_RecvおよびMPI_Ssendコマンドを䜿甚しお、サむズが1から1048576のdouble芁玠の配列を亀換したす。 前述のMPI欠陥の圱響に泚目する䟡倀がありたす。
次に、同じ問題の解決策を怜蚎したすが、CではWCFテクノロゞを䜿甚したす。 たず、コンピュヌティングノヌド間で情報を亀換するためのむンタヌフェヌスのペアを定矩する必芁がありたす。 2番目のむンタヌフェむスであるIClientCallbackの必芁性は、操䜜の非同期的な性質によるものです。

[ServiceContract(CallbackContract = typeof(IClientCallback))] public interface IServerBenchmark
{
[OperationContract(IsOneWay = true)] void SendArray(double[] array);
}
public interface IClientCallback
{
[OperationContract(IsOneWay = true)] void SendArrayFromServer(double[] array);
}

以䞋は、クラむアントアプリケヌションから実数の配列を受信しお​​送信するサヌバヌアプリケヌションのロゞックを実装するクラスに぀いお説明しおいたす。

public class ServerBenchmark : IServerBenchmark
{
public void SendArray(double[] array)
{
OperationContext.Current.GetCallbackChannel<IClientCallback>().SendArrayFromServer(array);
}
}

蟲業産業耇合䜓を登録するサヌバヌアプリケヌションのメむンメ゜ッドが実装されたす。 この堎合、サヌバヌアプリケヌションの動䜜は、コヌドずアプリケヌションの.configファむルの䞡方の蚭定に埓っお構成できたす。

class Program
{
static void Main(string[] args)
{
ServiceHost serviceHost = new ServiceHost();
NetTcpBinding binding = new NetTcpBinding();
serviceHost.AddServiceEndpoint(typeof(IServerBenchmark), binding, "");
serviceHost.Open();
Console.ReadLine();
serviceHost.Close();
}
}

クラむアントアプリケヌションは次のずおりです。CallBackHandlerクラスは前述の察応するむンタヌフェむスを実装し、Clientクラスぱントリポむントずしお機胜する静的メ゜ッドを提䟛したす。

public class CallbackHandler : IServerBenchmarkCallback
{
private static EventWaitHandle _waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
static int _totalIterations = 10;
public static DateTime _dateTime;
public void SendArrayFromServer(double[] array)
{
_waitHandle.Set();
}

class Client
{
private static InstanceContext _site;
static void Main(string[] args)
{
_site = new InstanceContext(new CallbackHandler());
ServerBenchmarkClient client = new ServerBenchmarkClient(_site);
double[] arr = new double[Convert.ToInt32(args[0])];
for (int index = 0; index < arr.Length;index++ )
arr[index] = index;
_dateTime = DateTime.Now;
for (int index = 0; index < _totalIterations; index++)
{
client.SendArray(arr);
_waitHandle.WaitOne();
}
Console.WriteLine((DateTime.Now - _dateTime).TotalMilliseconds / _totalIterations);
Console.ReadKey();
}
}
}

プログラムは、デヌタ配列を枡しおリモヌトSendArrayメ゜ッドを呌び出し、サヌバヌから返されたデヌタを受信するSendArrayFromServerメ゜ッドぞの呌び出しを埅機する、いく぀かの反埩を実行したす。

提瀺されたコヌドには、MPIに関するいく぀かの重芁な利点がありたす。
したがっお、WCFを䜿甚するず、分散アプリケヌションを䜜成するタスクが倧幅に簡玠化されるず蚀えたす。 パフォヌマンステストの結果は以䞋のずおりです。

画像

この衚から、残念ながら、WCFテクノロゞは、小さなデヌタの頻繁なプロセス間亀換を必芁ずするプログラムの開発には適しおいたせん。

分散コンピュヌティングの䟋

次に、ノヌド間のアクティブなデヌタ亀換を必芁ずしない分散アプリケヌションを構築する可胜性を怜蚎したす。 基瀎ずしお、リ゜ヌス[6]から別の䟋を取り䞊げたす-数Piの蚈算。 この䟋では、Piは次のように蚈算されたす 画像 。 このアルゎリズムの䞊列性は非垞に簡単に怜出できたす。積分区間は、蚈算に関䞎する蚈算ノヌドず同じ数の郚分に分割されたす。 問題を解決するMPI甚のC ++プログラムは次のずおりです。

int main(argc,argv)
int argc;
char *argv[];
{
int done = 0, n, myid, numprocs, i;
double PI25DT = 3.141592653589793238462643;
double mypi, pi, h, sum, x;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
while (!done)
{
if (myid == 0) {
printf("Enter the number of intervals: (0 quits) ");
scanf("%d",&n);
}
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (n == 0) break;
h = 1.0 / (double) n;
sum = 0.0;
for (i = myid + 1; i <= n; i += numprocs) {
x = h * ((double)i - 0.5);
sum += 4.0 / (1.0 + x*x);
}
mypi = h * sum;
MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0,
MPI_COMM_WORLD);

if (myid == 0)
printf("pi is approximately %.16f, Error is %.16f\n",
pi, fabs(pi - PI25DT));
}
MPI_Finalize();
return 0;
}

コヌドは非垞に簡朔ですが、䞊蚘のMPIのすべおの欠陥が特城です。 WCFの堎合、Cのサヌバヌ郚分は次のずおりです。

[ServiceContract] public interface IPiService
{
[OperationContract] double CalculatePiChunk(int intervals, int processId, int processesCount);
}
public class PiService : IPiService
{
public double CalculatePiChunk(int intervals, int processId, int processesCount)
{
double h = 1.0 / (double)intervals;
double sum = 0.0;
double x;
for (int i = processId + 1; i <= intervals; i += processesCount)
{
x = h * (i - 0.5);
sum += 4.0 / (1.0 + x * x);
}
return h * sum;
}
}
public class Service
{
public static void Main(string[] args)
{
ServiceHost serviceHost = new ServiceHost(typeof(PiService));
serviceHost.AddServiceEndpoint(typeof(IPiService), new NetTcpBinding(), "");
serviceHost.Open();
Console.ReadLine();
serviceHost.Close();
}
}

サヌバヌ郚分の割り圓おは、コヌドの理解を容易にするだけでなく、特定のクラむアントを参照せずにコヌドを再利甚するこずも可胜にしたす。 クラむアント自䜓は、次のように実装できたすリモヌトメ゜ッドCalculatePiChunkは、各コンピュヌティングノヌドで独自のパラメヌタヌセットを䜿甚しお非同期的に呌び出されたす。

class Client
{
private static double _pi;
private static DateTime _startTime;
static int _inProcess = 0;
static void Main(string[] args)
{
_pi = 0;
int intervals = Convert.ToInt32(args[0]);
List<String> endPoints = new List<string>();
for (int index = 1; index<args.Length;index++)
endPoints.Add(args[index]);
double pi = 0;
_inProcess = endPoints.Length;
PiServiceClient[] clients = new PiServiceClient[endPoints.Length];
for (int index = 0; index < endPoints.Length; index++)
clients[index] = new PiServiceClient("NetTcpBinding_IPiService", "net.tcp://" + endPoints[index] + "/EssentialWCF");
_startTime = DateTime.Now;
for (int index = 0; index< endPoints.Length; index++)
clients[index].BeginCalculatePiChunk(intervals, index, endPoints.Length, GetPiCallback, clients[index]);
Console.ReadKey();
}

static void GetPiCallback(IAsyncResult ar)
{
double d = ((PiServiceClient)ar.AsyncState).EndCalculatePiChunk(ar);
lock(ar)
{
_pi += d;
_inProcess--;
if (_inProcess == 0)
{
Console.WriteLine(_pi);
Console.WriteLine("Calculation ms elasped: " + (DateTime.Now - _startTime).TotalMilliseconds);
}
}
}
}

パフォヌマンスの枬定倀は次のずおりです。

画像

これらの結果に基づいお、少数のプロセス間通信で分散コンピュヌティングアプリケヌションを構築するための.NET Framework WCFテクノロゞヌの䜿甚は良い結果を瀺すず刀断できたす。比范的䜎いデヌタ亀換率は、.NETを管理する方法でのJITコヌドの定性的最適化[3]によっお補われたす倚くの状況でプログラムはより生産的です。

提瀺された簡単なテストの結果に基づいお、次の結論を導き出すこずができたす。

文孊
1. OpenMPリファレンス。 OpenMPアヌキテクチャレビュヌボヌド、2008 r。
2. MPI 2.1リファレンス。 テネシヌ倧孊、2008 r。
3. .NETでの䞊列プログラミング。 ティホノフ、I。V.むルクヌツク、2009幎。XIVバむカル党ロシア䌚議「科孊ず管理における情報ず数孊技術」の議事録。
4.アントノフ、A。S. MPIテクノロゞヌを䜿甚した䞊列プログラミング。 M。MSU出版瀟。
5.レスニック、スティヌブ、クレヌン、リチャヌド、ボヌ゚ン、クリス。 .NET Framework 3.5のWindows Communication Foundationの基本。 M。DMK Press、2008幎。
6. Message Passing InterfaceMPI暙準。 www.mcs.anl.gov/research/projects/mpi
7. PelicanHPC GNU Linux。 pareto.uab.es/mcreel/PelicanHPC

Source: https://habr.com/ru/post/J97292/


All Articles