rb2_lab2x

advertisement
НИЖЕГОРОДСКИЙ ГОСУДАРСТВЕННЫЙ
ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ им. Р.Е.Алексеева
Дисциплина "Робтотехника"
Отчет
по лабораторной работе № 2
Тема: "Распределённые вычисления"
Вариант 9
Выполнил студент группы 10-В-1
Сидоренко О.О.
Проверил:
Гай В.Е.
Н. Новгород
2013 г.
Постановка задачи
Требуется разработать распределённую систему для решения
вычислительной задачи. Такая система должна включать сервисы двух
типов: координирующий (MainService) и вычислительный (CompService).
Требования к координирующему сервису:
1) существует только один экземпляр координирующего сервиса;
2) координирующий сервис запускает вычислительные сервисы на
узлах, раздаёт им задания и собирает результаты вычислений с каждого
узла, завершает вычислительные сервисы.
Требования к вычислительному сервису:
1) на одной ЭВМ может быть запущено несколько DSS узлов для
запуска вычислительных сервисов;
2) вычислительный сервис принимает задание, выполняет
вычисления и отправляет результат обработки на координирующий сервис;
Задание: Разработать алгоритм умножения матрицы a (m × n элементов) на
n
вектор b (n элементов) по следующей формуле: ci   aijb j ,1  i  m . При
j 1
разработке параллельного алгоритма необходимо учитывать, что значение
i-го элемента вектора c не зависит от значений других элементов вектора
2
Листинг. Координирующий сервис.
//MainService.cs
using
using
using
using
using
using
using
using
System;
System.Collections.Generic;
System.ComponentModel;
Microsoft.Ccr.Core;
Microsoft.Dss.Core.Attributes;
Microsoft.Dss.ServiceModel.Dssp;
Microsoft.Dss.ServiceModel.DsspServiceBase;
W3C.Soap;
using
using
using
using
using
submgr = Microsoft.Dss.Services.SubscriptionManager;
compSrv = CompService.Proxy;
ds = Microsoft.Dss.Services.Directory;
cs = Microsoft.Dss.Services.Constructor;
System.Xml;
namespace MainService
{
[Contract(Contract.Identifier)]
[DisplayName("MainService")]
[Description("MainService service (no description provided)")]
class MainService : DsspServiceBase
{
/// <summary>
/// Service state
/// </summary>
[ServiceState]
MainServiceState _state = new MainServiceState();
/// <summary>
/// Main service port
/// </summary>
[ServicePort("/MainService", AllowMultipleInstances = false)]
MainServiceOperations _mainPort = new MainServiceOperations();
[SubscriptionManagerPartner]
submgr.SubscriptionManagerPort _submgrPort = new submgr.SubscriptionManagerPort();
/// <summary>
/// Service constructor
/// </summary>
public MainService(DsspServiceCreationPort creationPort)
: base(creationPort)
{
}
int c = 2;
string[] names;
//
compSrv.CompServiceOperations[] _compSrvPort;
compSrv.CompServiceOperations[] _compSrvNotify;
compSrv.Subscribe[] subscribe;
Port<int> complPort = new Port<int>();
ds.DirectoryPort[] remoteDir;
cs.ConstructorPort[] remoteConstructor;
ds.Query[] query;
ds.QueryResponseType[] queryRsp;
cs.Create[] create;
CreateResponse[] createRsp;
string[] compService;
XmlQualifiedName[] namex;
PartnerType[] remote;
/// <summary>
/// Service start
/// </summary>
protected override void Start()
{
if (_state == null)
_state = new MainServiceState();
base.Start();
3
names = System.IO.File.ReadAllLines(@"K:\Lab2\main.txt");
_compSrvPort = new compSrv.CompServiceOperations[c];
_compSrvNotify = new compSrv.CompServiceOperations[c];
subscribe = new compSrv.Subscribe[c];
remoteDir = new ds.DirectoryPort[c];
remoteConstructor = new cs.ConstructorPort[c];
query = new ds.Query[c];
queryRsp = new ds.QueryResponseType[c];
create = new cs.Create[c];
createRsp = new CreateResponse[c];
compService = new string[c];
namex = new XmlQualifiedName[c];
remote = new PartnerType[c];
for (int i = 0; i < c; i++)
{
_compSrvPort[i] = new compSrv.CompServiceOperations();
_compSrvNotify[i] = new compSrv.CompServiceOperations();
}
for (int i = 0; i < c; i++)
// обработчик Replace сообщения, полученного от вычислительного сервиса
Activate<ITask>(
Arbiter.Receive<compSrv.Replace>(true, _compSrvNotify[i], RemoteNotifyReplaceHandler)
);
Arbiter.Activate(Environment.TaskQueue, Arbiter.MultipleItemReceive(
true, complPort, c, delegate(int[] array)
{
LogInfo("Коорд. серв.: данные от выч. серв. получены");
for (int i = 0; i < 10; i++)
LogInfo(_state.c[i].ToString());
// отправка сообщений на завершение вычислительным сервисам
for (int i = 0; i < c; i++)
{
_compSrvPort[i].DsspDefaultDrop();
_compSrvPort[i] = null;
}
}));
/////////////////////////////////////////////
//// начало формирования состояния сервиса, в котором находится вся информация о вычислительной задаче
// PC, port
// номера портов должны соответствовать соглашению указанному: различаться на 1 только.
/////////////////////////////////////////////
// формируется список узлов, на которых будет запущен вычислительный сервис
_state.NodeList.Add(new MainServiceState.NodeElement(names[0], Convert.ToInt32(names[1]), 0));
_state.NodeList.Add(new MainServiceState.NodeElement(names[2], Convert.ToInt32(names[3]), 1));
// формируется вычислительное задание для каждого узла
_state.ClArr = new HelpClass[c];
int a1 = 10; // строки
int b1 = 10; // столбцы
for (int i = 0; i < c; i++)
_state.ClArr[i] = new HelpClass();
_state.ClArr[0].a = 0;
_state.ClArr[0].b = a1 / 2 - 1;
_state.ClArr[1].a = a1 / 2;
_state.ClArr[1].b = a1 - 1;
_state.A = new int[a1, b1];
_state.B = new int[b1];
_state.c = new int[a1];
for (int i = 0; i < a1; i++)
{
for (int j = 0; j < b1; j++)
_state.A[i, j] = i + j;
}
for (int j = 0; j < b1; j++)
_state.B[j] = j;
4
// запускается вычислительный процесс
SpawnIterator(OnStartup);
}
/// <summary>
/// Handles Subscribe messages
/// </summary>
/// <param name="subscribe">the subscribe request</param>
// этот обработчик обрабатывает запросы на подписку, отправляемые 7 сервису от 4 сервиса
// при получении запроса на подписку выполняется сама подписка, далее // 7 сервис отправляет 4 своё состояние, в котором находится вся информация о вычислительной задаче
[ServiceHandler(ServiceHandlerBehavior.Concurrent)]
public IEnumerator<ITask> SubscribeHandler(Subscribe subscribe)
{
SubscribeRequestType request = subscribe.Body;
LogInfo("Коорд. серв.: запрос подписки от: " + request.Subscriber);
// использование Subscription Manager для управления подписками
yield return Arbiter.Choice(
SubscribeHelper(_submgrPort, request, subscribe.ResponsePort),
delegate(SuccessResult success)
{
// Send a notification on successful subscription so that the
// subscriber can initialize its own state
base.SendNotificationToTarget<Replace>(request.Subscriber, _submgrPort, _state);
},
delegate(Exception e)
{
LogError(null, "Коорд. серв.: ошибка при подписке к выч. серв.", e);
}
);
yield break;
}
// итератор OnStartup запускает на указанном узле вычислительные сервисы,
// выполняет подписку координирующего сервиса на сообщения вычислительных сервисов
private IEnumerator<ITask> OnStartup()
{
string[] nms = new String[c];
string[] rmt = new String[c];
nms[0]
nms[1]
rmt[0]
rmt[1]
=
=
=
=
"http://schemas.tempuri.org/2013/05/mainservice.html:Remote";
"http://schemas.tempuri.org/2013/05/mainservice.html:Remote";
"http://"+names[0]+":"+names[1]+"/directory";
"http://"+names[2]+":"+names[3]+"/directory";
// Это позволяет управлять любым количеством сервисов
for (int i = 0; i < c; i++)
{
namex[i] = new XmlQualifiedName(nms[i]);
remote[i] = new PartnerType(namex[i], null, rmt[i]);
}
/////// тут начало цикла, хотя можно было сделать и раньше
for (int i = 0; i < c; i++)
{
remoteDir[i] = DirectoryPort;
if (remote[i] != null && !string.IsNullOrEmpty(remote[i].Service))
{
remoteDir[i] = ServiceForwarder<ds.DirectoryPort>(remote[i].Service);
}
remoteConstructor[i] = ConstructorPort;
query[i] = new ds.Query(
new ds.QueryRequestType(
new ServiceInfoType(cs.Contract.Identifier)
)
);
remoteDir[i].Post(query[i]);
yield return (Choice)query[i].ResponsePort;
queryRsp[i] = query[i].ResponsePort;
if (queryRsp[i] != null)
{
5
remoteConstructor[i] =
ServiceForwarder<cs.ConstructorPort>(queryRsp[i].RecordList[0].Service);
}
compService[i] = null;
create[i] = new cs.Create(new ServiceInfoType(compSrv.Contract.Identifier));
remoteConstructor[i].Post(create[i]);
yield return (Choice)create[i].ResponsePort;
createRsp[i] = create[i].ResponsePort;
if (createRsp[i] != null)
{
compService[i] = createRsp[i].Service;
}
else
{
LogError((Fault)create[i].ResponsePort);
yield break;
}
_compSrvPort[i] = ServiceForwarder<compSrv.CompServiceOperations>(compService[i]);
yield return _compSrvPort[i].Subscribe(_compSrvNotify[i], out subscribe[i]);
if ((Fault)subscribe[i].ResponsePort != null)
LogError("Коорд. серв.: ошибка при подписке на уведомления выч. серв.",
(Fault)subscribe[i].ResponsePort);
else
LogInfo("Коорд. серв.: подписка на уведомления выч. серв. выполнена");
}
}
// обработчик, запускаемый при получении Replace сообщения от вычислительного сервиса
private void RemoteNotifyReplaceHandler(compSrv.Replace replace)
{
// объединяем результаты, полученные от вычислительного сервиса
// и записываем их в результирующий массив
int id = replace.Body._id;
int _aa1 = _state.ClArr[id].a;
int _bb1 = _state.ClArr[id].b;
LogInfo("Коорд. серв.: получены данные от " + replace.Body._id + " __ " + _aa1 + " to "
+ _bb1);
for (int i = _aa1; i <= _bb1; i++)
{
_state.c[i] = replace.Body._c[i];
LogInfo(replace.Body._c[i].ToString());
}
// отправка в порт завершения сообщения о том, что пришли данные с одного из
// вычислительных сервисов
complPort.Post(1);
}
/// <summary>
/// обработчик Replace сообщения
/// </summary>
[ServiceHandler(ServiceHandlerBehavior.Exclusive)]
public IEnumerator<ITask> ReplaceHandler(Replace replace)
{
_state = replace.Body;
// отправка сообщения Replace всем подписчикам
base.SendNotification(_submgrPort, replace);
replace.ResponsePort.Post(DefaultReplaceResponseType.Instance);
yield break;
}
[ServiceHandler(ServiceHandlerBehavior.Teardown)]
public IEnumerator<ITask> DropHandler(DsspDefaultDrop drop)
{
base.DefaultDropHandler(drop);
yield break;
}
}
}
//MainServiceTypes.cs
using System;
6
using
using
using
using
using
using
using
System.Collections.Generic;
System.ComponentModel;
Microsoft.Ccr.Core;
Microsoft.Dss.Core.Attributes;
Microsoft.Dss.ServiceModel.Dssp;
Microsoft.Dss.ServiceModel.DsspServiceBase;
W3C.Soap;
namespace MainService
{
/// <summary>
/// MainService contract class
/// </summary>
public sealed class Contract
{
/// <summary>
/// DSS contract identifer for MainService
/// </summary>
[DataMember]
public const string Identifier = "http://schemas.tempuri.org/2013/05/mainservice.html";
}
// вспомогательный класс
// используется в качестве типа списка для хранения параметров
[DataContract]
public class HelpClass
{
[DataMember]
public int a; // начало диапазона
[DataMember]
public int b; // конец диапазона
}
/// <summary>
/// MainService state
/// </summary>
[DataContract]
public class MainServiceState
{
// описание структуры данных, рассылаемой вычислительным узлам
// здесь указывается идентификатор для узла и порта/
// на одном компьютере могут запускаться несколько узлов
[DataContract]
public struct NodeElement
{
[DataMember]
public string pc;
[DataMember]
public int port;
[DataMember]
public int id;
public NodeElement(string p1, int p2, int p3)
{
pc = p1;
port = p2;
id = p3;
}
}
private List<NodeElement> _NodeList = new List<NodeElement>();
[DataMember(IsRequired = true)]
public List<NodeElement> NodeList
{
get { return _NodeList; }
set { _NodeList = value; }
}
// массивы которые отправляются на вычислительные сервисы
[DataMember(IsRequired = true)]
public int[,] A;
[DataMember(IsRequired = true)]
public int[] B;
[DataMember(IsRequired = true)]
public int[] c;
7
// массив параметров
[DataMember(IsRequired = true)]
public HelpClass[] ClArr;
}
/// <summary>
/// MainService main operations port
/// </summary>
[ServicePort]
public class MainServiceOperations : PortSet<DsspDefaultLookup, DsspDefaultDrop, Get, Subscribe, Replace>
{
}
/// <summary>
/// MainService get operation
/// </summary>
public class Get : Get<GetRequestType, PortSet<MainServiceState, Fault>>
{
/// <summary>
/// Creates a new instance of Get
/// </summary>
public Get()
{
}
/// <summary>
/// Creates a new instance of Get
/// </summary>
/// <param name="body">the request message body</param>
public Get(GetRequestType body)
: base(body)
{
}
/// <summary>
/// Creates a new instance of Get
/// </summary>
/// <param name="body">the request message body</param>
/// <param name="responsePort">the response port for the request</param>
public Get(GetRequestType body, PortSet<MainServiceState, Fault> responsePort)
: base(body, responsePort)
{
}
}
/// <summary>
/// MainService subscribe operation
/// </summary>
///
public class Subscribe : Subscribe<SubscribeRequestType, PortSet<SubscribeResponseType, Fault>>
{
}
/// <summary>
/// MainService replace operation
/// </summary>
public class Replace : Replace<MainServiceState, PortSet<DefaultReplaceResponseType, Fault>>
{
}
}
8
Листинг. Вычислительный сервис.
//CompService.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Ccr.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;
using Microsoft.Dss.ServiceModel.DsspServiceBase;
using W3C.Soap;
//операторы для управления сервисом
using submgr = Microsoft.Dss.Services.SubscriptionManager;
using mainSrv = MainService.Proxy;
using ds = Microsoft.Dss.Services.Directory;
using cs = Microsoft.Dss.Services.Constructor;
using System.Net;
using Microsoft.Dss.Core;
namespace CompService
{
[Contract(Contract.Identifier)]
[DisplayName("CompService")]
[Description("CompService service (no description provided)")]
class CompService : DsspServiceBase
{
/// <summary>
/// Service state
/// </summary>
[ServiceState]
CompServiceState _state = new CompServiceState();
/// <summary>
/// Main service port
/// </summary>
[ServicePort("/CompService", AllowMultipleInstances = true)]
CompServiceOperations _mainPort = new CompServiceOperations();
[SubscriptionManagerPartner]
submgr.SubscriptionManagerPort _submgrPort = new submgr.SubscriptionManagerPort();
/// <summary>
/// Service constructor
/// </summary>
public CompService(DsspServiceCreationPort creationPort)
: base(creationPort)
{
}
mainSrv.MainServiceOperations _mainSrvPort = new mainSrv.MainServiceOperations();
mainSrv.MainServiceOperations _mainSrvNotify = new mainSrv.MainServiceOperations();
mainSrv.Subscribe subscribe = new mainSrv.Subscribe();
/// <summary>
/// Service start
/// </summary>
protected override void Start()
{
//
// Add service specific initialization here
//
if (_state == null)
_state = new CompServiceState();
base.Start();
//в итераторе запускается подписка на уведомления коорд. сервиса
SpawnIterator(OnStartup);
Activate<ITask>(Arbiter.Receive<mainSrv.Replace>(true, _mainSrvNotify,
RemoteNotifyReplaceHandler));
}
9
ServiceInfoType[] list = null;
private IEnumerator<ITask> OnStartup()
{
string[] names = System.IO.File.ReadAllLines(@"K:\Lab2\comp.txt");
// подключение к узлу
// ip-адрес
string machine = names[0];
// TCP порт для передачи HTTP запросов
ushort nport = Convert.ToUInt16(names[1]);
// создание URI сервиса
UriBuilder builder = new UriBuilder(Schemes.DsspTcp, machine, nport, ServicePaths.InstanceDirectory);
ds.DirectoryPort fport = ServiceForwarder<ds.DirectoryPort>(builder.Uri);
//создание и отправка Get-запроса
ds.Get get = new ds.Get();
fport.Post(get);
//обработка результата запроса
yield return Arbiter.Choice(get.ResponsePort,
delegate(ds.GetResponseType response)
{
list = response.RecordList;
},
delegate(Fault fault)
{
list = new ServiceInfoType[0];
LogError(fault);
}
);
//количество найденных сервисов
int cnt = 0;
//массив, хранящий информацию об найденных сервисах
ServiceInfoType[] servList = new ServiceInfoType[cnt];
foreach (ServiceInfoType info in list)
{
if (info.Contract == mainSrv.Contract.Identifier)
{
Array.Resize(ref servList, servList.Length + 1);
servList[cnt] = info;
cnt += 1;
}
}
_mainSrvPort = ServiceForwarder<mainSrv.MainServiceOperations>(
servList[0].Service);
subscribe.NotificationPort = _mainSrvNotify;
//отправка запроса на подписку
_mainSrvPort.Post(subscribe);
//обработка результата запроса
yield return Arbiter.Choice(
subscribe.ResponsePort,
delegate(SubscribeResponseType response)
{
LogInfo("Выч. серв. подписан на " + servList[0].Service);
},
delegate(Fault fault)
{
LogError("Выч. серв. " + fault);
}
);
yield break;
}
private void RemoteNotifyReplaceHandler(mainSrv.Replace replace)
{
LogInfo("Выч. серв.: получено Replace сообщение от коорд. сервиса");
// определение идентификатора экземпляра вычислительного сервиса
Dictionary<string, string> env = Environment.ServiceUriTable;
string addr = " ";
foreach (KeyValuePair<string, string> pair in env)
{
addr = pair.Value;
break;
10
}
string[] splitAddr = addr.Split('/');
string pcinfo = splitAddr[2];
string[] info = pcinfo.Split(':');
string pc = info[0];
string port = info[1];
int id = -1;
foreach (mainSrv.MainServiceState.NodeElement xx in replace.Body.NodeList)
{
if (((xx.port + 1).ToString() == port) && (xx.pc.ToString() == pc))
{
id = xx.id;
break;
}
}
LogInfo("Выч. серв.: идентификатор сервиса: " + id.ToString());
int aa1 = replace.Body.ClArr[id].a;
int bb1 = replace.Body.ClArr[id].b;
c = new int[replace.Body.c.Length];
Port<int> p = new Port<int>();
Receiver r = Arbiter.Receive(false, p, delegate(int n)
{
Replace resReplace = new Replace();
_state._c = c;
_state._id = id;
resReplace.Body = _state;
base.SendNotification(_submgrPort, resReplace);
});
Activate(r);
// формирование вычислительного задания
HelpStruct pr = new HelpStruct(replace.Body.ClArr[id].a,
replace.Body.ClArr[id].b, replace.Body.b, replace.Body.A);
// запуск задачи на выполнение
Arbiter.ExecuteToCompletion(Environment.TaskQueue,
new IterativeTask<Port<int>, HelpStruct>(p, pr, CalcHandler));
}
public struct HelpStruct
{
public int _a, _b;
public int[] B;
public int[,] A;
public HelpStruct(int p1, int p2, int[] p3, int[,] p5)
{
_a = p1;
_b = p2;
B = p3;
A = p5;
}
}
// переменная, хранящая результат вычислений
int[] c;
//выполняет вычисления на основе задания от коорд. сервиса
IEnumerator<ITask> CalcHandler(Port<int> port, HelpStruct p)
{
for (int i = p._a; i <= p._b; i++)
{
c[i] = 0;
for (int j = 0; j < p.B.Length; j++)
{
c[i] += p.A[i, j] * p.B[j];
}
LogInfo("C ===" + c[i].ToString());
}
port.Post(1);
11
yield break;
}
[ServiceHandler(ServiceHandlerBehavior.Teardown)]
public virtual IEnumerator<ITask> DropHandler(DsspDefaultDrop drop)
{
Console.WriteLine("Выч. серв. завершил свою работу");
base.DefaultDropHandler(drop);
//ControlPanelPort.Shutdown();
yield break;
}
/// <summary>
/// Handles Subscribe messages
/// </summary>
/// <param name="subscribe">the subscribe request</param>
[ServiceHandler(ServiceHandlerBehavior.Concurrent)]
public IEnumerator<ITask> SubscribeHandler(Subscribe subscribe)
{
SubscribeRequestType request = subscribe.Body;
LogInfo("Выч. серв.: запрос подписки от: " + request.Subscriber);
//здесь также используется менеджер подписок
yield return Arbiter.Choice(
SubscribeHelper(_submgrPort, request, subscribe.ResponsePort),
delegate(SuccessResult success)
{
LogInfo("Выч. серв.: Подписка выполнена");
},
delegate(Exception e)
{
LogError(null, "Выч. серв.: подписка не выполнена", e);
}
);
yield break;
}
/// <summary>
/// Обработчик Replace сообщения
/// </summary>
[ServiceHandler(ServiceHandlerBehavior.Exclusive)]
public IEnumerator<ITask> ReplaceHandler(Replace replace)
{
_state = replace.Body;
base.SendNotification(_submgrPort, replace);
replace.ResponsePort.Post(DefaultReplaceResponseType.Instance);
yield break;
}
}
}
//CompServiceTypes.cs
using
using
using
using
using
using
using
using
System;
System.Collections.Generic;
System.ComponentModel;
Microsoft.Ccr.Core;
Microsoft.Dss.Core.Attributes;
Microsoft.Dss.ServiceModel.Dssp;
Microsoft.Dss.ServiceModel.DsspServiceBase;
W3C.Soap;
namespace CompService
{
/// <summary>
/// CompService contract class
/// </summary>
public sealed class Contract
{
/// <summary>
/// DSS contract identifer for CompService
/// </summary>
[DataMember]
public const string Identifier = "http://schemas.tempuri.org/2013/05/compservice.html";
}
/// <summary>
12
/// CompService state
/// </summary>
[DataContract]
public class CompServiceState
{
// результат вычислений
[DataMember]
public int[] _c;
// идентификатор вычислительного сервиса
[DataMember]
public int _id;
}
/// <summary>
/// CompService main operations port
/// </summary>
[ServicePort]
public class CompServiceOperations : PortSet<DsspDefaultLookup, DsspDefaultDrop, Get, Subscribe, Replace>
{
}
/// <summary>
/// CompService get operation
/// </summary>
public class Get : Get<GetRequestType, PortSet<CompServiceState, Fault>>
{
/// <summary>
/// Creates a new instance of Get
/// </summary>
public Get()
{
}
/// <summary>
/// Creates a new instance of Get
/// </summary>
/// <param name="body">the request message body</param>
public Get(GetRequestType body)
: base(body)
{
}
/// <summary>
/// Creates a new instance of Get
/// </summary>
/// <param name="body">the request message body</param>
/// <param name="responsePort">the response port for the request</param>
public Get(GetRequestType body, PortSet<CompServiceState, Fault> responsePort)
: base(body, responsePort)
{
}
}
/// <summary>
/// CompService subscribe operation
/// </summary>
public class Subscribe : Subscribe<SubscribeRequestType, PortSet<SubscribeResponseType, Fault>>
{
}
/// <summary>
/// CompService replace operation
/// </summary>
public class Replace : Replace<CompServiceState, PortSet<DefaultReplaceResponseType, Fault>>
{
}
}
13
Результат работы программы
Вычислительный сервис №1:
Вычислительный сервис №2:
Координирующий сервис:
14
Отладочные сообщения вычислительного сервиса №1:
Отладочные сообщения вычислительного сервиса №2:
15
Отладочные сообщения координирующего сервиса:
16
Download