Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Регистрация Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Автокомплит

Как что-то сделать, при этом ничего не делая
Оценить эту запись

Очередной загрузчик. Часть 1.

Запись от gloomyBrain размещена 04.12.2012 в 16:34
Обновил(-а) gloomyBrain 14.12.2012 в 19:34

Пытаюсь каламбурить. Ну или напустить двусмысленности в название темы. В чем она может проявляться - эта двусмысленность - сейчас постараюсь объяснить. Стоит также заметить, что материал ждал публикации примерно год, просто не доходили руки. Исправляюсь =)

Итак, начнем с постановки задачи:
- нужно загружать "что-то"
- "что-то" может быть абсолютно чем угодно
- "что-то" может обрабатываться в процессе загрузки
- нужно четко контроллировать количество одновременных загрузок
- нужно уметь обрабатывать ошибки
- прогрессом загрузки каждого отдельного "что-то" можно пока пренебречь

Сначала я рассуждал так:
Цитата:
Вот нам нужно что-то загрузить, значит мы для начала сделаем интерфейс загрузчика, который будет иметь методы load(url), getContent() и еще что-то. И вот эти загрузчики нужно будет собрать вместе и контроллировать в одном СуперЗагрузчике
Попробовал. Не понравилось. Ну вы понимаете - юношеский максимализм он с возрастом только крепчает. Стал думать дальше и в конечном итоге пришла вот такая мысль:
Цитата:
Нам не нужна загрузка вообще. Нам нужно выполнять какие-то действия в каком-то порядке. И иногда эти действия будут загрузкой, иногда нет. Нам нужна очередь!
Ага, есть идея, давайте дробить ее на составляющие. Лучше всего нам подойдет старинный паттерн "команда". Для тех кто не знаком и кому лень читать заумную википедию, могу рассказать на примере из книги Колина Мука:
Цитата:
Мама уходя из дома пишет список домашних дел Папе и детям. Для этого она берет конверты и подписывает каждый конверт: этот для Маши, этот для Коли, а вот этот для Папы. Внутри каждого из конвертов лежит листок бумаги со списком дел для того, кто указан на конверте.
Все предельно просто - есть задача и есть исполнитель. Объединение двух этих вещей и есть команда.

И все же, к составляющим (а то уже килобайт текста и ни строчки кода). Начнем с интерфейса нашей команды. Только я сразу оговорюсь, что далее буду называть это заданием, а не командой. Ну да невелика разница.

Итак, интерфейс задания:
Код AS3:
package nq.utils.task {
 
	/**
	 * Интерфейс для заданий, выполнение которых идет по очерди
	 * 
	 * @author gloomyBrain
	 */
	public interface ITask {
 
		/**
		 * Проритет задания
		 */
		function get priority():int;
 
		/**
		 * Начать выполнение задания
		 */
		function start():void;
 
	}
 
}
Так как задания у нас могут быть еще и асинхронными, давайте придумаем интерфейс и для них:
Код AS3:
package nq.utils.task {
 
	import flash.events.IEventDispatcher;
 
	/**
	 * Событие успешного завершения задания
	 */
	[Event(name = "complete", type = "flash.events.Event")]
 
	/**
	 * Событие прерывания задания
	 */
	[Event(name = "cancel", type = "flash.events.Event")]
 
	/**
	 * Интерфейс для асинхронных заданий
	 * 
	 * @author gloomyBrain
	 */
	public interface IAsyncTask extends ITask, IEventDispatcher {
 
		/**
		 * Остановить выполнение задания
		 */
		function stop():void;
 
	}
 
}
Как видно из примера выше, асинхронные задания отличаются от всех остальных тем, что
а) могут быть прерваны в любой момент
б) отправляют события при старте и прерывании (причина прерывания не рассматривается)

Так же стоит упомянуть о приоритетах. В постановке задачи у нас было "выполнять в каком-то порядке". Так вот, один из способов упорядочивания - это приоритеты. Чем больше приоритет, тем раньше будем выполнять задание.

Ну что, все подготовительные этапы пройдены, давайте думать как будем делать очередь заданий. Я для себя решил что это будет IEventDispatcher (то есть по природе своей асинхронный объект) с возможностью добавлять и удалять задания в любой момент. Так же, по моим представлениям, должна быть возможность регулировать количество одновременно исполняемых заданий. Да, кстати, говоря о параллельных заданиях - мы будем считать, что параллельно могут выполняться только асинхронные задания (IAsyncTask). Обычные задания (ITask) считаются выполненными, как только был вызван метод start(). То есть если проводить аналогии, то ITask - это вызов метода, а IAsyncTask - это начало ожидания собыия.
Перечень свойств очереди заданий:
- конструктор TaskQueue(maxThreads:uint = 1, usePriority:Boolean = false)
- методы start(), stop(), get isRunning() для контроля над процессом
- методы addTask(), removeTask() для планирования/удаления заданий
- ... ну и еще всякие приятные мелочи.

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

В следующий раз напишем загрузчик с использованием нашей очереди заданий.
Вложения
Тип файла: zip nq.zip (12.4 Кб, 150 просмотров)
Размещено в flash.net , flash.utils
Комментарии 9 Отправить другу ссылку на эту запись
Всего комментариев 9

Комментарии

Старый 04.12.2012 19:51 goWalk вне форума
goWalk
Очень полезно. Спасибо за оптимальный вариант
Старый 04.12.2012 20:08 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Да! Это очень близко к моим мыслям вообще, но мои не ограничиваются загрузчиком.
Должен быть некоторый конвеер, но очень крутой. В него заносятся таски.
Причем таск может быть как методом, так задачей (ITask как раз). Метод точно исполняется синхронно, задачи – в зависимости от их реализации. Причем ITaskQueue, который и является этим конвеером, сам является ITask, таким образом внутри него можно вкладывать другой конвеер.
В моём идеальном мире это действительно очень круто при проектировании, например, пошаговых социалок.
1) Спросить кто я такой
2) Узнать моих друзей
3) Связаться с сервером
4) Проинициализировать вьюхи

Задачи выполняются одна за другой, только вот 2-ю и 3-ю можно распараллелить.
Код AS3:
new TaskQueue().add(new AskWhoIAm(), new TaskParallel(new MyFriends(), new ConnectToServer()), _view.init);
К сожалению, я ограничился созданием такой системы только для общении с соц. сетями. Это масштабно, но сил и времени реализовывать – нет.

В общем, отлично. Мне эта тема по нраву!
Старый 04.12.2012 20:15 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Цитата:
Это очень близко к моим мыслям вообще, но мои не ограничиваются загрузчиком.
Ну мои, в общем-то, тоже. Я поэтому и выложил сначала очередь.

Цитата:
Причем ITaskQueue, который и является этим конвеером, сам является ITask, таким образом внутри него можно вкладывать другой конвеер.
В ощем случае интерфейс не нужен, можно же написать свой таск, внутри которого будет очередь. А очередь - это всегда что-то конкретное. С тем API что есть сейчас уже можно делать все что угодно, вложенности и тд.
Старый 04.12.2012 21:14 TanaTiX вне форума
TanaTiX
 
Аватар для TanaTiX
У меня тоже есть похожие разработки. Помню, основной проблемой была передача данных в результате окончания работы какой-то таски. А вот на счет назначения приоритетов я не заморачивался. Все же загрузка контента ИМХО чуть более специфичная задача, чем просто очередность заданий.
Старый 04.12.2012 21:51 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Я принципиально отказался от передачи данных между заданиями. По крайней мере, очередь об этом ничего не знает. Как я буду делать паралльельные вызовы, если мне нужно сохранять результат для передачи? И кому я буду его передавать? - я же не знаю какие еще задания есть в очереди. В общем, проанализировав вышеописанное, я решил что таск и сам в состоянии записать любые данные куда ему хочется. И сам в состоянии подождать, пока эти данные появятся.
Старый 07.12.2012 02:14 Котяра вне форума
Котяра
 
Аватар для Котяра
Цитата:
Должен быть некоторый конвеер, но очень крутой.
посмотри на http://www.as3commons.org/as3-common...roduction.html
Код AS3:
var task:Task = new Task()
.and(new FirstCommand())
.and(new SecondCommand())
.next(new ThirdCommand())
.next(new FourthCommand());
 
task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete);
task.execute();
Код AS3:
var task:Task = new Task();
 
task.if_(new ConditionProvider())
 .next(new FirstCommand())
 .else_()
 .next(new SecondCommand())
.end();
 
task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete);
task.execute();
и
Код AS3:
var task:Task = new Task();
 
task.while_(new MyConditionProvider())
 .next(new FirstCommand())
.end();
 
task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete);
task.execute();
песня же)
Обновил(-а) Котяра 07.12.2012 в 11:32
Старый 07.12.2012 02:18 Котяра вне форума
Котяра
 
Аватар для Котяра
Цитата:
У меня тоже есть похожие разработки. Помню, основной проблемой была передача данных в результате окончания работы какой-то таски.
Я это решил созданием общего объекта контекст и передачей его в нужные команды и таски.
Старый 10.12.2012 14:27 ChuwY вне форума
ChuwY
 
Аватар для ChuwY
Только один совет-просьба насчет оформления.
Когда выполнена вторая часть статьи, хотелось бы видеть ссылку на нее в конце первой.
Старый 14.12.2012 19:36 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Добавил ссылочку. Но вторая часть не пользуется популярностью ввиду... не знаю ввиду чего =)
 

 


Часовой пояс GMT +4, время: 01:16.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.