Re[45]: пример eao197: "сообщения" рвут "разделяемую память"
От: Gaperton http://gaperton.livejournal.com
Дата: 05.12.08 13:28
Оценка: :)
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, Gaperton, Вы писали:


G>>Вопрос по существу — ты сказал, что реализация очереди будет "избыточнее", чем то неизвестно что, что ты там планируешь в данной задаче вместо нее применять. Докажи.


E>В разговоре с Siclair я несколько раз упоминал использование atomic_read. И он понял о чем я говорю, поскольку идея очень простая.


Sinclair не просто понял, о чем ты говоришь (это дело нехитрое), он, если ты не заметил, еще и объяснил тебе, почему ты неправ со своим atomic_read.

Мне очень жаль, но это совершенно очевидно будет работать медленнее, чем мое решение на очередях сообщений. Потому, что у меня будет просто обычный read на каждый lookup. Я думал, еще раз тебе этого объяснять не стоит, и ты придумал что-то новенькое?
Re[46]: пример eao197: "сообщения" рвут "разделяемую память"
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 05.12.08 13:33
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Sinclair не просто понял, о чем ты говоришь (это дело нехитрое), он, если ты не заметил, еще и объяснил тебе, почему ты неправ со своим atomic_read.


Может быть тогда ты сможешь сказать, у какой именно очереди сообщений накладные расходы на проверку наличия нового элемента будут меньше одного atomic_read?


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[47]: пример eao197: "сообщения" рвут "разделяемую память"
От: Gaperton http://gaperton.livejournal.com
Дата: 05.12.08 13:52
Оценка:
Здравствуйте, eao197, Вы писали:

E>>>Как и 7% преимущества в скорости. Известная песня.


G>>7% преимущества в скорости — это и правда фигня полная


E>Это полная фигня на словах в форуме.


Про то, что 7% это "не фигня" — пионерам рассказывай, ладно? На практике 7% называется "одинаковая производительность", и никто не будет расшибаться в лепешку, чтобы эти 7% ликвидировать.

E>На практике, ты не сможешь этот выигрыш нивелировать.

На практике, смогу. Если захочу. В любом случае, тебе-то откуда знать, что я смогу а что нет.

G>>(особенно по сравнению с проигрышем OpenMP на примерно 140% в одном тесте, что ты предпочел забыть)


E>Я не забыл. Проигрыш OpenMP всего лишь доказывает, что не всегда у разделяемой памяти есть преимущества. Но ты забыл, что этого здесь никто и не отрицал.


Да? Тогда прокомментируй еще вот это:

А уж по поводу ситуации, где нам надо только считать данные — обмен сообщениями (на любых очередях), так и останется медленнее на несколько порядков.


G>>Задача, которую ты описал — это малюсенькая часть функциональности контакт-центра.


E>Ее масштаб вовсе не является преградой к тому, чтобы на ее примере показать наличие преимуществ у разделяемой памяти.


Так вэлкам! Что ж ты никак не покажешь-то эти преимущества? Что тогда для тебя преградой то является, а?
Re[47]: пример eao197: "сообщения" рвут "разделяемую память"
От: Gaperton http://gaperton.livejournal.com
Дата: 05.12.08 13:59
Оценка:
Здравствуйте, eao197, Вы писали:

G>>Sinclair не просто понял, о чем ты говоришь (это дело нехитрое), он, если ты не заметил, еще и объяснил тебе, почему ты неправ со своим atomic_read.


E>Может быть тогда ты сможешь сказать, у какой именно очереди сообщений накладные расходы на проверку наличия нового элемента будут меньше одного atomic_read?


Может быть, я тебе это уже сказал во второй части своего сообщения, которую ты предусмотрительно вырезал? Может быть, Синклер тебе все то же самое объяснил?

G>Мне очень жаль, но это совершенно очевидно будет работать медленнее, чем мое решение на очередях сообщений. Потому, что у меня будет просто обычный read на каждый lookup. Я думал, еще раз тебе этого объяснять не стоит, и ты придумал что-то новенькое?


Ты что, не знаешь, что atomic_read заметно медленнее обычного read? Может быть, ты наконец перестанешь прикидываться валенком? Обкакался, так будь мужиком, блин, и имей смелость это признать. Тем более — это всего лишь форум, и всего знать невозможно. Я был о тебе лучшего мнения, короче.
Re[43]: Можно
От: Gaperton http://gaperton.livejournal.com
Дата: 05.12.08 14:48
Оценка:
Здравствуйте, EvilChild, Вы писали:

S>>Хорошо, worker получил пакет, в котором 100 транзакций, каждая из которых читает дерево. Выполнил — полез в очередь — получил новое дерево — поехал дальше.

EC>А почему нельзя перед обработкой пакета тупо скопировать ссылку себе на стек?

Почему нельзя? Можно. Получишь в точности очередь сообщений, а именно — ее предельный случай с глубиной 1 и полиси вытеснения при переполнении по FIFO — что станет совершенно очевидно даже тем, кто в танке, если завернуть то что получится в класс, и посмотреть на функциональный интерфейс.

Потом можно пойти еще дальше, упереться, и под разными предлогами не называть это очередью сообщений. Видишь ли, asynchronous message passing — это не более чем дизайн-идиома, которая в конечном счете на современных архитектурах все равно превратится в те примитивы, через которые реализуются семафоры все остальное. Так же, как программа на функциональном языке в конечном счете превратится в ассемблерные инструкции.

Если использовать это как аргумент, все закончится Теоремой Существования Дворкина (http://rsdn.ru/forum/message/3194838.1.aspx
Автор: Sinclair
Дата: 01.12.08
), на которую любят опираться люди, которым с пеной у рта нечего сказать. Ну так что на таких время тратить — только портить.
Re[44]: Можно
От: EvilChild Ниоткуда  
Дата: 06.12.08 11:35
Оценка: +1
Здравствуйте, Gaperton, Вы писали:

EC>>А почему нельзя перед обработкой пакета тупо скопировать ссылку себе на стек?


G>Почему нельзя? Можно. Получишь в точности очередь сообщений, а именно — ее предельный случай с глубиной 1 и полиси вытеснения при переполнении по FIFO — что станет совершенно очевидно даже тем, кто в танке, если завернуть то что получится в класс, и посмотреть на функциональный интерфейс.

Можно и о скаляре думать как об одномерном массиве с одним элементом, вопрос в том когда такой взгляд на вещи полезен.
G>Потом можно пойти еще дальше, упереться, и под разными предлогами не называть это очередью сообщений.
Я ниразу не против называть это очередью.
Я спрашивал не в разрезе вашего увлекательного спора message passing vs shared memory,
а исключительно в контексте конкретного решения с иммутабельным деревом.
G>Видишь ли, asynchronous message passing — это не более чем дизайн-идиома, которая в конечном счете на современных архитектурах все равно превратится в те примитивы, через которые реализуются семафоры все остальное. Так же, как программа на функциональном языке в конечном счете превратится в ассемблерные инструкции.
Мне кажется важным различать то, в каких терминах мы можем думать о решении и то, как оно реализуется.

G>Если использовать это как аргумент, все закончится Теоремой Существования Дворкина (http://rsdn.ru/forum/message/3194838.1.aspx
Автор: Sinclair
Дата: 01.12.08
), на которую любят опираться люди, которым с пеной у рта нечего сказать. Ну так что на таких время тратить — только портить.

Что вы так Дворкина любите пинать? Я с ним во многих случаях тоже не согласен, это же не повот его пинать по любому поводу.
now playing: Ralph Sliwinski — Freak & Muscle
Re[45]: Можно
От: Gaperton http://gaperton.livejournal.com
Дата: 06.12.08 15:58
Оценка: 13 (2) -1
Здравствуйте, EvilChild, Вы писали:

EC>>>А почему нельзя перед обработкой пакета тупо скопировать ссылку себе на стек?


G>>Почему нельзя? Можно. Получишь в точности очередь сообщений, а именно — ее предельный случай с глубиной 1 и полиси вытеснения при переполнении по FIFO — что станет совершенно очевидно даже тем, кто в танке, если завернуть то что получится в класс, и посмотреть на функциональный интерфейс.

EC>Можно и о скаляре думать как об одномерном массиве с одним элементом, вопрос в том когда такой взгляд на вещи полезен.

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

Данный объект по всем своим свойствам объективно является мэйлбоксом для приема асинхронных сообщений, и в данном случае употребляется в том контексте, где применяется мэйлбокс. Подобного рода мэйлбоксы на одно сообщения — распространенная вещь в дизайне на асинхронных сообщениях. А вот, например, семафор по всем своим свойствам мэйлбоксом не является.

Характерный пример — во время обработки какого-либо сообщения, процесс хочет выполнить RPC-вызов. Для этого, он отправляет сообщение процессу, и встает в блокирующее ожидание на мэйлбокс. Второй процесс выполняет запрос, и возвращает результат. Один. В виде одного объекта. В указанный мэйлбокс, специально для этого созданный.

В случае Эрланга, где присутствует сопоставление с образцом и селективный receive, заводить явно этого mailbox не надо. Достаточно написать:

rpc_call( CalleePID, Method, ArgList ) ->
CalleePID ! { self(), Method, ArgList },
receive { CalleePID, Result } -> Result.

И не важно, свалятся в мэйлбокс во время выполнения RPC другие запросы, или нет. В случае тех языков, где selective receive не поддержан, например, Java, C++, и C#, для приема результата разумные люди заводят отдельный мэйлбокс в вызывающем процессе. Что, кстати, еще и эффективнее.

И разумеется, полной очереди здесь создавать не обязательно — здесь гарантированно хватит специального мэйлбокса, рассчитанного на одно сообщение. Групповой receive в данном случае на группе мэйлбоксов изобразить также возможно, кстати, — он ждет первого сообщения из любой из указанных очередей. Получишь почти полный изоморфизм с моделью Эрланга, и характерными для него приемами проектирования.

А то, какую именно реализацию очереди ты применяешь в каждом конкретном случае — исключительно вопрос оптимизации, а не модели программирования. И более того, количество разных видов этих очередей сильно конечно.

G>>Потом можно пойти еще дальше, упереться, и под разными предлогами не называть это очередью сообщений.

EC>Я ниразу не против называть это очередью.
EC>Я спрашивал не в разрезе вашего увлекательного спора message passing vs shared memory,
EC>а исключительно в контексте конкретного решения с иммутабельным деревом.

В контексте данного примера — речь об предварительной оптимизации, дающей совершенно мизерный эффект на общую производительность, в силу небольшого потока данных по данному каналу в сравнении с основным. Конкретнее, речь идет о специальной оптимизированной реализации подобного мэйлбокса на одно сообщение, соответствующего мультикаст-группе.

G>>Видишь ли, asynchronous message passing — это не более чем дизайн-идиома, которая в конечном счете на современных архитектурах все равно превратится в те примитивы, через которые реализуются семафоры все остальное. Так же, как программа на функциональном языке в конечном счете превратится в ассемблерные инструкции.

EC>Мне кажется важным различать то, в каких терминах мы можем думать о решении и то, как оно реализуется.

А мне кажется важным применять в разработке фреймворки, которые позволяют тебе делать реализацию решения в тех терминах, в которых формулируется решение. Боюсь, я не один, кому так кажется.

G>>Если использовать это как аргумент, все закончится Теоремой Существования Дворкина (http://rsdn.ru/forum/message/3194838.1.aspx
Автор: Sinclair
Дата: 01.12.08
), на которую любят опираться люди, которым с пеной у рта нечего сказать. Ну так что на таких время тратить — только портить.

EC>Что вы так Дворкина любите пинать? Я с ним во многих случаях тоже не согласен, это же не повот его пинать по любому поводу.

Я в данном случае "пинаю" не Дворкина.
Re: Java Parallel computing: multicore, Erlang, Scala
От: SuperRockStar  
Дата: 07.12.08 04:06
Оценка:
А кто-нибудь использовал вот эту штуку
http://en.wikipedia.org/wiki/Yaws_(web_server)

Судя по всему Apache умирает там где живет Yaws, написанный на Erlang.
Re[46]: Offtop
От: kdw Россия  
Дата: 07.12.08 07:31
Оценка: -5 :))
Достал ты уже со своим ерлангом , Я не ничего не имею против ассинхронных сообщений (сделать это можно на любом языле я думаю)
Как абстракции на нем писать предлагаешь , можно конешно через жопу (и на асемблере можно), Но в данном
случае например предпочитаю нормальные обьектно ориентированные языки.

Я смотрел на синтаксис ерланга и чесно говоря он него тошнит , хотя в некоторых случаях думаю имеет смысл
заюзать.

G>В случае Эрланга, где присутствует сопоставление с образцом и селективный receive, заводить явно этого mailbox не надо. Достаточно написать:


G>rpc_call( CalleePID, Method, ArgList ) ->

G>CalleePID ! { self(), Method, ArgList },
G>receive { CalleePID, Result } -> Result.
Re[47]: Offtop
От: Gaperton http://gaperton.livejournal.com
Дата: 07.12.08 12:09
Оценка: +1
Здравствуйте, kdw, Вы писали:

kdw>Достал ты уже со своим ерлангом,


Так не читай мои посты. Кто-то заставляет?

kdw>Как абстракции на нем писать предлагаешь , можно конешно через жопу (и на асемблере можно), Но в данном

kdw>случае например предпочитаю нормальные обьектно ориентированные языки.

С чего ты взял, что я тебе что-то предлагаю.

kdw>Я смотрел на синтаксис ерланга и чесно говоря он него тошнит , хотя в некоторых случаях думаю имеет смысл

заюзать.

Меня совершенно не трогают твои предпочтения, предположения, душевные терзания, и от чего именно тебя тошнит.
Re[48]: Offtop
От: kdw Россия  
Дата: 07.12.08 12:22
Оценка: -2
Здравствуйте, Gaperton, Вы писали:

G>Так не читай мои посты. Кто-то заставляет?


Кроме тебя в этом форуме есть и другие люди ,

как ты себе представляешь чьи то посты читать а чьи то нет.

вот приходиться и твои читать.
Re[49]: Offtop
От: Gaperton http://gaperton.livejournal.com
Дата: 07.12.08 12:37
Оценка:
Здравствуйте, kdw, Вы писали:

G>>Так не читай мои посты. Кто-то заставляет?


kdw>Кроме тебя в этом форуме есть и другие люди ,

kdw>как ты себе представляешь чьи то посты читать а чьи то нет.
kdw>вот приходиться и твои читать.

Значит, прими касторки. Мне, знаешь, пофигу, читаешь ты, не читаешь.
Re[46]: А можно еще лучше
От: Gaperton http://gaperton.livejournal.com
Дата: 07.12.08 23:02
Оценка: 9 (3) -1
Здравствуйте, Gaperton, Вы писали:

G>Характерный пример — во время обработки какого-либо сообщения, процесс хочет выполнить RPC-вызов. Для этого, он отправляет сообщение процессу, и встает в блокирующее ожидание на мэйлбокс. Второй процесс выполняет запрос, и возвращает результат. Один. В виде одного объекта. В указанный мэйлбокс, специально для этого созданный.


G>В случае Эрланга, где присутствует сопоставление с образцом и селективный receive, заводить явно этого mailbox не надо. Достаточно написать:


G>rpc_call( CalleePID, Method, ArgList ) ->

G>CalleePID ! { self(), Method, ArgList },
G>receive { CalleePID, Result } -> Result.

G>И не важно, свалятся в мэйлбокс во время выполнения RPC другие запросы, или нет. В случае тех языков, где selective receive не поддержан, например, Java, C++, и C#, для приема результата разумные люди заводят отдельный мэйлбокс в вызывающем процессе. Что, кстати, еще и эффективнее.


G>И разумеется, полной очереди здесь создавать не обязательно — здесь гарантированно хватит специального мэйлбокса, рассчитанного на одно сообщение. Групповой receive в данном случае на группе мэйлбоксов изобразить также возможно, кстати, — он ждет первого сообщения из любой из указанных очередей. Получишь почти полный изоморфизм с моделью Эрланга, и характерными для него приемами проектирования.


Собственно, я не сказал вам самого интересного про эти однообъектные мэйлбоксы. У них есть специальное название — фьючерс. И они сами по себе представляют интересную концепцию, настолько, что она достойна поддержания на уровне языка.

Фьючерс — это значение, которое будет вычислено. Его вычисление форсируется в момент первого обращения к фьючерсу. Это обобщение ленивых вычислений и асинхронного межпроцессного взаимодействия.

То есть, в случае примера с RPC — мы просим другой процесс асинхронно обработать наш запрос, положив результат во фьючерс. И, когда мы попробуем из фьючерса что-то считать, а там ничего нет — то мы встанем в блокирующее ожидание.

Более интересный пример, демонстрирующий силу фьючерсов. Допустим, мы хотим рассчитать массив из десяти значений. Каждое — параллельно. Мы просто заполняем этот массив в цикле фьючерсами, каждый из которых — RPC-вызов к какому-то потоку (или старт отдельного потока, выполняющего рассчет, возможно — асинхронный старт, по мере доступности потоков в пуле). И все. Потом — просто пользуемся массивом, не выставляя никакой явной синхронизации, и не принимая сообщений. Допустим, так же пробегаемся по нему в цикле, считая сумму.

При этом, мы можем сделать вычисление не параллельным, а "ленивым", чтобы оно вычислялось в момент обращения. Программа будет выглядеть так же.

Фьючерсы — это совершенно потрясающая модель, дружественная к асинхронным сообщениям и тому стилю программирования, про который я сейчас рассказал, но еще более высокоуровневая, и в еще меньшей степени подверженная ошибкам. Пример того, как фьючерсы поддержаны в языке, можно увидеть в Alice ML.

Читаем про фьючерсы здесь.
http://en.wikipedia.org/wiki/Future_(programming)

Я думаю, фьючерсы — это лучшее, что придумано на текущий момент в области языкостроения и параллельного программирования.
Re[47]: А можно еще лучше
От: C0s Россия  
Дата: 08.12.08 00:29
Оценка: +1
Здравствуйте, Gaperton, Вы писали:

G>Более интересный пример, демонстрирующий силу фьючерсов. Допустим, мы хотим рассчитать массив из десяти значений. Каждое — параллельно. Мы просто заполняем этот массив в цикле фьючерсами, каждый из которых — RPC-вызов к какому-то потоку (или старт отдельного потока, выполняющего рассчет, возможно — асинхронный старт, по мере доступности потоков в пуле). И все. Потом — просто пользуемся массивом, не выставляя никакой явной синхронизации, и не принимая сообщений. Допустим, так же пробегаемся по нему в цикле, считая сумму.


что характерно, все эти, действительно полезные вещи, скажем, в java доступны на уровне стандартной библиотеки, начиная с версии 5. т.е. я хочу сказать, что это не какое-то вчерашнее открытие, раз есть давно и в таком популярном языке

что касается их применения, то мне доводилось использовать Future в реализациях протоколов уровня приложения с возможностью ожидания подтверждения от контрагента для более, чем одного посланного пакета (windowing > 1)
Re[47]: А можно еще лучше
От: Cyberax Марс  
Дата: 08.12.08 00:47
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Я думаю, фьючерсы — это лучшее, что придумано на текущий момент в области языкостроения и параллельного программирования.

До тех пор, пока код фьючерса не попробует обращаться к разделяемой памяти...
Sapienti sat!
Re[47]: Фьючерсы на Эрланге
От: Gaperton http://gaperton.livejournal.com
Дата: 08.12.08 00:59
Оценка:
Хардкорный Эрланг. Добавляем туда самые настоящие, честные фьючера и ленивые вычисления. Две процедуры, которые возвращают фьючерс. Фьючерс — это функция без аргументов. Ее можно вызывать многократно, ничего страшного не произойдет, она вычисляет результат только один раз. Поэтому, в функции-фьючере допустимы побочные эффекты.

Даю две функции — первая вычисляется параллельно и энергично, вторая — тупое ленивое вычисление.
Функция eval — служебная, решение полагается на замыкания и словарь процессов. Внимание — код писан в один проход и не проверен, может не сработать.

concurrent_eval( F ) ->
    PID = spawn( F ),
    
    Eval = fun() ->
        receive { PID, Result } -> Result end
    end,
    
    fun() -> eval( PID, Eval ) end.

lazy_eval( F ) ->
    fun() -> eval( F, F ) end.

eval( Key, F ) ->
    case get( Key ) of
        none -> put( Key, Result = F() ), Result;
        Value -> Value
    end.
Re[48]: Фьючерсы на Эрланге - v2
От: Gaperton http://gaperton.livejournal.com
Дата: 08.12.08 01:20
Оценка:
Хм... Подчеркнем-ка мы явно связь между ленивыми вычислениями и параллелизмом...

lazy_eval( F ) ->
   fun() ->
      case get( F ) of
         none -> put( F, Result = F() ), Result;
         Value -> Value
      end
   end.

concurrent_eval( F ) ->
    PID = spawn( F ),
    Receive = fun() ->
        receive { PID, Result } -> Result end
    end,
    lazy_eval( Receive ).


Вот так-то оно лучше. Проще и понятнее.
Re[49]: Фьючерсы на Эрланге - rpc
От: Gaperton http://gaperton.livejournal.com
Дата: 08.12.08 01:38
Оценка:
Здравствуйте, Gaperton, Вы писали:

И добавим rpc-фьючерс.

rpc_future( PID, Message ) ->
        PID ! Message,
    Receive = fun() ->
        receive { PID, Result } -> Result end
    end,
    lazy_eval( Receive ).


Правда, эта реализация с багой. Багу вызывает использование внутри lazy_eval аргумента в качестве ключа, что выйдет боком в случае аргумента с побочным эффектом. Здесь надо что-то придумать. Самое надежное — использовать в качестве ключа уникальный номер с автоинкрементом, который генерировался бы внутри lazy_eval. Однако, правильнее дать программисту над этим контроль.

Однако, думаю, идея понятна. RPC в таком стиле мне нравится даже в Эрланге. Приятный rpc. И более эффективный в том плане, что не режет параллелизм. В чем, собственно, и состоит преимущество фьючерсов.
Re[48]: и еще баг
От: Gaperton http://gaperton.livejournal.com
Дата: 08.12.08 01:52
Оценка:
Забыл передать аргументом новому процессу self(). И ваще, послать результат обратно . Но мысль мне нравится. Надо ее думать. Кажется, что-то похожее предлагал Армстронг со своим оператором bang-bang, и вроде как написал специальный модуль.

G>
G>concurrent_eval( F ) ->
G>    PID = spawn( F ),
хъ
Re[48]: А можно еще лучше
От: Gaperton http://gaperton.livejournal.com
Дата: 08.12.08 02:06
Оценка:
Здравствуйте, C0s, Вы писали:

G>>Более интересный пример, демонстрирующий силу фьючерсов. Допустим, мы хотим рассчитать массив из десяти значений. Каждое — параллельно. Мы просто заполняем этот массив в цикле фьючерсами, каждый из которых — RPC-вызов к какому-то потоку (или старт отдельного потока, выполняющего рассчет, возможно — асинхронный старт, по мере доступности потоков в пуле). И все. Потом — просто пользуемся массивом, не выставляя никакой явной синхронизации, и не принимая сообщений. Допустим, так же пробегаемся по нему в цикле, считая сумму.


C0s>что характерно, все эти, действительно полезные вещи, скажем, в java доступны на уровне стандартной библиотеки, начиная с версии 5. т.е. я хочу сказать, что это не какое-то вчерашнее открытие, раз есть давно и в таком популярном языке


Вообще, в этом деле довольно мало вещей, которые являются вчерашним открытием. Фьючерсы были известны в 80-х. Кажется. А про асинхронные сообщения Дийкстра писал ваще черт знает когда. Просто тема параллельного программирования пошла в мэйнстрим относительно недавно, с приходом в жизнь многоядерных мультитредных процов. Рядовому программеру просто не нужно было этого всего знать еще 5 лет назад. Да и сейчас в массе своей обходятся. Пока Нехалемы с Ниагарами не стали обыденными вещами, вызывающими зевоту.

Ну, это же очень хорошо, что они уже есть в библиотеке. Это означает, что можно начинать их "правильно готовить" немедленно . А если б их не было, их несложно было б добавить. Мое мнение — давно пора.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.