OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Четверг, 28 Март, 2024 14:34

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 11 ] 
Автор Сообщение
 Заголовок сообщения: Как сделать аналог Wait?
СообщениеДобавлено: Понедельник, 30 Март, 2009 12:23 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
Есть программа, которая должна скачивать из сети несколько файлов. Сначала были использованы блокирующие функции для работы с сетью, основным недостатком данного метода было то, что интерфейс пользователя никак не реагировал, в то время, пока работали блокирующие функции. После чего плокирующие функции были заменены на неблокирующие, при этом интерфейс пользователя перестал блокироваться. Теперь требуется скачивать файлы последовательно (то есть следующий файл начинает скачиваться только после предыдущего), но в неблокирующем режиме.
Одним из вариантов является следующий псевдокод:

PROCEDURE (c: NetworkClient) Do-;
VAR Net2: NetworkClient;
BEGIN
IF файл скачался THEN
(* Скачиваем следующий файл *)
NEW(Net2);
Net2.GetFile(Какие-то параметры);
Services.DoLater(Net2, Services.Ticks() + Services.resolution);
ELSE
Services.DoLater(c, Services.Ticks() + Services.resolution);
END

END Do;

PROCEDURE Start;
VAR Net: NetworkClient;
BEGIN
NEW(Net);
Net.GetFile(какие-то параметры);
Services.DoLater(Net, Services.Ticks() + Services.resolution);
END Start;

Но данный метод мне не очень нравится, так как приходится использовать рекурсию там, где цикла вполне хватило бы. В идеале хотелось бы иметь следущий код:

PROCEDURE Start;
VAR i: INTEGER;
Net: NetworkClient;
BEGIN
New(Net);
FOR i := 0 TO N DO
Net.GetFile(Address[i], SaveAsFile[i]);
Services.DoLater(Inet, Services.Ticks() + Services.resolution);
Services.WaitUntilEnd();
END;
END Start;

То есть хочется чтобы файлы скачивались последовательно, но в неблокирующем режиме, то есть чтобы интерфейс пользователя не блокировался.

Можно ли такое сделать? Может быть есть какие-нибудь другие похожие методы, решающие ту же проблему?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как сделать аналог Wait?
СообщениеДобавлено: Понедельник, 30 Март, 2009 14:46 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Я бы сделал так:

Код:
DownloadAction = POINTER TO RECORD(Services.Action)
   list : (* список файлов для скачивания, и всего, что необходимо для работы *)
   currentFile : (* какой либо указатель на текущий файл*)
END;

PROCEDURE(da : DownloadAction) Do;
BEGIN
   IF ФайлЗагружен(da.currentFile) THEN
      da.currentFile:=СледующийФайл();
   ELSIF ~ФайлЗагружен(da.curentFile) THEN
      ЗагрузитьЧасть(da.currentFile)
   END;
   IF ~ВсеФайлыЗагружены(da.list) THEN Services.DoLater(da, Services.now) END
END Do;

PROCEDURE Start;
VAR da : DownloadAction;
BEGIN
   NEW(da); da.list:=... da.currsntFile:=(первый файл)
   Services.DoLater(da, Services.now) (запускаем наше действие в свободное плавание)
END Start;


Такой вопрос, а вы используете подсистему Comm для работы с сетью? Насколько я знаю, она изначально неблокирующая.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как сделать аналог Wait?
СообщениеДобавлено: Понедельник, 30 Март, 2009 15:33 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
Пётр Кушнир писал(а):
Такой вопрос, а вы используете подсистему Comm для работы с сетью? Насколько я знаю, она изначально неблокирующая.


Я использовал модуль CommTCPAsync с сайта: http://www.zinnamturm.eu/downloadsDH.htm#Dbu
Хотя этот модуль решает проблему блокировки функций, при создании подключения, функция GetFile из этого модуля блокирует работу среды до полного скачивания файла. Но там же в комментариях сказано, что это легко переделать на неблокирующую работу, что я и сделал.

Насчет вашего решения, в принципе оно похоже на первое решение, которое я привёл. Я знаю, что так можно сделать. Но почему-то мне такое решение кажется некрасивым, так как вместо простого циклического подхода используется рекурсивный подход.

Я почитал форум, понял что, вопрос, который я задал, лучше было бы задать в секции: "Параллельное и многопоточное программирование". Понял что тема параллельного программирования достаточно сложна, но тем не менее прочитанное натолкнуло меня на еще одно решение. Здесь приведен простенький модуль, который должен сначала распечатать цифры от 0 до 4 с интервалом в одну секунду, после чего распечатать прочерки. Суть решения в вызове Services.actionHook.Step в цикле, что как я думаю и является аналогом функции Wait о которой я спрашивал.

MODULE MyAsyncModule;

IMPORT Log, Services;

TYPE
Async = POINTER TO RECORD (Services.Action)
counter: INTEGER;
END;

VAR
b: BOOLEAN;

PROCEDURE (a: Async) Do-;
BEGIN
IF a.counter < 5 THEN
Log.Int(a.counter); Log.Ln;
INC(a.counter);
Services.DoLater(a, Services.Ticks()+Services.resolution);
ELSE
b := TRUE;
END;
END Do;

PROCEDURE Start*;
VAR a: Async;
BEGIN
b := FALSE;
NEW(a);
a.counter := 0;
Services.DoLater(a, Services.Ticks()+Services.resolution);
WHILE ~b DO
Services.actionHook.Step;
END;
Log.String("-------------------------"); Log.Ln;
END Start;

END MyAsyncModule.

Насколько правильно/неправильно данное решение? Какие могут быть минусы?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как сделать аналог Wait?
СообщениеДобавлено: Понедельник, 30 Март, 2009 16:12 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Rifat писал(а):
вместо простого циклического подхода используется рекурсивный подход
Нет, по моему, получается как раз цикл, нигде нет рекурсивного вызова, посмотрите внимательнее, Services.DoLater это не вызов, это добавление в очередь.

Я не знаю структуры вашего приложения, но разумный аналог Wait - это переназначение действия до того момента, как выполнится какое-либо условие(то, что у вас в первом примере).

с CommTCPAsync я как-то работал, у него какие-то проблемы с Vista были, поэтому отказался. По-моему вам стоит поработать с CommTCP, и возможно с буферами от А. Ильина. Хотя бы в режиме демки, так станет понятнее, как работать с сетью.

Я когда осваивал, наклепал себе демку, может вам пригодится:
В модуле ObxStreamsServer надо запустить коммандер Start, после этого в модуле ObxStreamsClient надо запустить коммандер Send -- получится пересылка файла. Поможет понять принцип.


Вложения:
Mod.zip [4.34 КБ]
Скачиваний: 406
Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как сделать аналог Wait?
СообщениеДобавлено: Понедельник, 30 Март, 2009 16:23 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
Пётр Кушнир писал(а):
Rifat писал(а):
вместо простого циклического подхода используется рекурсивный подход


с CommTCPAsync я как-то работал, у него какие-то проблемы с Vista были, поэтому отказался. По-моему вам стоит поработать с CommTCP, и возможно с буферами от А. Ильина. Хотя бы в режиме демки, так станет понятнее, как работать с сетью.

Я когда осваивал, наклепал себе демку, может вам пригодится:

На Vista я пока не тестировал, может когда буду тестировать на Vista ваша демка пригодиться.

Насчет последовательности скачиваний, думаю, все-таки буду делать как в вашем примере.

То решение, которое я нашел:
WHILE ~b DO
Services.actionHook.Step;
END;
работает, конечно, лучше, чем WHILE ~b DO END;
но интерфейс пользователя все равно блокируется, думаю что надо бы добавить еще одну команду в цикл
WHILE ~b DO
Services.actionHook.Step;
Обработать оконные события;
END;
но не знаю какую функцию вызвать.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как сделать аналог Wait?
СообщениеДобавлено: Понедельник, 30 Март, 2009 16:28 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Порекомендую вам изучить демку прямо сейчас, она к висте не имеет отношения.
Не поверите, но мне вообще не надо в своём приложении обрабатывать оконные события, обращаться к Services.actionHook. В демке как раз использование общих, доступных средств. вместо вывода в лог вы можете вызывать Dialog.Update для интерактора прогресс-бара.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как сделать аналог Wait?
СообщениеДобавлено: Понедельник, 30 Март, 2009 16:59 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
Пётр Кушнир писал(а):
Порекомендую вам изучить демку прямо сейчас, она к висте не имеет отношения.
Не поверите, но мне вообще не надо в своём приложении обрабатывать оконные события, обращаться к Services.actionHook. В демке как раз использование общих, доступных средств. вместо вывода в лог вы можете вызывать Dialog.Update для интерактора прогресс-бара.


Посмотрел вашу реализацию, в общем понятно что и как работает. Единственное, что у Вас модуль ...Client занимается отправкой файла, а мне же требуется скачивать файл.

Я понимаю, что чтобы сделать скачивание нескольких файлов в общем случае не нужны ни Services.actionHook, ни обработка оконных сообщений. Просто мне кажется, что с перенесением работы в функцию Do и использованием очереди получается немного запутанно, если новичек будет читать такой код, то он не сразу разберется. Согласен что с очередью очень хорошее решение, а главное правильное, при текущих ограничениях BlackBox-а.

Но у меня возникла мысль, что, возможно, как-то можно обойтись без очереди.
Цель была такой, чтобы код выглядел примерно так:

Установить адрес скачиваемого файла;
Начать скачивание файла в фоновом режиме;
Дождаться завершения скачивания файла;
Установить адрес другого скачиваемого файла;
Начать скачивание файла в фоновом режиме;
...

Но оказалось, что сделать функцию "Дождаться завершения скачивания файла", которая не будет блокировать работу всей среды, не так-то просто, а без нее получается, что 2 файла будут скачиваться параллельно, что иногда не очень желательно, особенно, если файлов не 2, а 50 или даже больше.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как сделать аналог Wait?
СообщениеДобавлено: Понедельник, 30 Март, 2009 17:13 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Rifat писал(а):
Client занимается отправкой файла, а мне же требуется скачивать файл
Вопрос реализации.
Rifat писал(а):
Просто мне кажется, что с перенесением работы в функцию Do и использованием очереди получается немного запутанно, если новичек будет читать такой код, то он не сразу разберется.
По-моему Отложенное Действие(Action) + переназначение как раз подходят для асинхронной работы, когда наперёд не знаешь, когда прилетит пакет из сети. Это довольно просто понять даже новичку. Ну и, необязательно ведь переносить всё в Do.
Rifat писал(а):
при текущих ограничениях BlackBox-а.
При каких?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как сделать аналог Wait?
СообщениеДобавлено: Понедельник, 30 Март, 2009 17:24 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 987
Откуда: Казань
Пётр Кушнир писал(а):
Rifat писал(а):
при текущих ограничениях BlackBox-а.
При каких?

Отсутствие функции Wait, о которой я спрашивал :)

Сам я не очень давно начал изучать BlackBox, но отсутствие такой функции, которая может дождаться завершения выполнения фоновой задачи мне показалось немного нелогичным. Желаемую последовательность действия я уже расписывал, вот если бы так можно было бы писать код, то это было наиболее логичным по моему мнению. Чем больше человек использует систему, тем больше ему кажется, что то что он делает наиболее просто и логично. В этом смысле у новичков глаз еще не "замылен" используемыми подходами.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как сделать аналог Wait?
СообщениеДобавлено: Понедельник, 30 Март, 2009 17:34 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
:D Тут возникает другой вопрос: А верно ли предположение о том, что такая функция должна присутствовать? Ведь фоновых задач(в том смысле, в котором их предполагает многозадачность) в ББ нет.

Но, как вы видите, и вашу задачу можно решить без многопоточности и без wait.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Как сделать аналог Wait?
СообщениеДобавлено: Понедельник, 30 Март, 2009 18:32 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 8500
Откуда: Троицк, Москва
Пётр Кушнир писал(а):
Я когда осваивал, наклепал себе демку, может вам пригодится:
Спасибо, пригодится.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 11 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB