Оберон-технология: особенности и перспективы |
Тематика обсуждения: Оберон-технология. Особенности, перспективы, практическое применение.
Всего в теме 6256 сообщений
Добавить свое сообщение
Отслеживать это обсуждение  Обсуждение из раздела Школа ОБЕРОНА
№ 6046 14-12-2007 18:28 |  |
Ответ на »сообщение 6045« (pepper)
___________________________
Это - не пример!
Это схема уже построенного цикла. Дайте мне этот цикл с содержанием - в 95% он может быть перестроен по грамотным правилам без вложенных проверок.
Споры про break тут уже бушевали... Народ не знает базовых схем алгоритмики и понятия инварианта и суёт свои "велосипеды", пытаясь доказать, что без break никак.
Вспомним Дейкстру "Дисциплину программирования" ( http://europrog.ru/book/dped1978r.pdf)
"Первейшим достоинством алгоритма является потенциальная компактность рассуждений, на которых может основываться проникновение в его сущность. Как только эта компактность потеряна, алгоритм в значительной степени теряет право на существование..."
и конкретно:
"Мы представляем себе функционирование конструкции S достаточно хорошо, если только знаем, как соответствующий ей преобразователь предикатов действует над любым постусловием".
Надо бы ввести отраслевой стандарт, чтобы каждый предлагающий свой вариант конструкции цикла (а вариантов циклов с выходом из середины ого сколько можно наизобретать - а на практике "наизобретовывают" ещё больше, чем я тут могу представить :-) ), обосновывал её право на существование, выводя для неё преобразователь предикатов. Пока не умахается для каждого "велосипеда" выводить. А иначе считать "алгоритм потерявшим право на существование" :-)
№ 6045 14-12-2007 18:03 |  |
Ответ на »сообщение 6039« (Илья Ермаков)
___________________________
А в С-шных программах break на break-е - а каждый break, как и goto - это палка в колёса оптимизатору.
Вот пример с кучей break:
while (condition1())
{
...
if (condition2())
break;
...
if (condition3())
break;
...
}
А вот без break:
bool flag2 = true;
bool flag3 = true;
while (condition1() && flag2 && flag3)
{
...
flag2 = condition2()
if (flag2)
{
...
flag3 = condition3();
if (flag3)
{
...
}
}
}
Вы всерьез думаете, что во втором случае у оптимизатора меньше работы? ;) Кстати, на этом же примере видно, как серьезно может пострадать читаемость, если возводить "правильность циклов без break" в догму. Особенно если писатель не придумал хороших названий для flag2 и flag3 ;)
P.S. Кстати, придумывание правильных названий занимает существенное время при кодировании. Поэтому чем их меньше и чем они локальнее - тем лучше.
№ 6044 14-12-2007 07:48 |  |
Ответ на »сообщение 6042« (Geniepro)
___________________________
>>> Вот любопытно, насколько просто или сложно будет это сделать, как стабильно это будет работать, и сколько времени будет потрачено на пересылку этих сообщений, как будет замедляться программа в зависимости от числа акторов сколько вообще акторов сможет максимально запуститься... В смысле, насколько легковесны Ваши акторы? ;о)
Вообщем, просто - сложно, понятия явно относительны. Мне это удалось сделать просто и быстро.
На счет стабильности - пересылка работает стабильно, но я заметил некоторые странности при удалении объектов. Спасибо за предложенный тест, буду разбираться.
Актеров запустить можно столько, сколько памяти есть в системе. Для 32-битных систем это около 5 млн., но это "голых". Если они будут нести в себе дополнительные данные, то их число соответственно уменьшится.
Также заметил факт отрицательной масштабируемости на многопроцессорной конфигурации. Также надо разобраться, с чем это связано...
Код программы:
Это полностью готовый к запуску код. Можно его подставить в пример ping-pong, либо создать новый проект на его основе.
Если что, то скачать пакет библиотеки acto, как всегда можно здесь:
http://sourceforge.net/projects/act-o
#include <multiprog.h>
#include <iostream>
#include <vector>
#include <conio.h>
using namespace multiprog;
// Кол-во элементов цепи
static const size_t NODES = 1000 * 1000;
static const size_t STOP_VALUE = 1 * 1000 * 1000;
// Desc: Узел цепи
class Node : public acto::implementation_t {
public:
struct msg_init : public acto::msg_t {
acto::actor_t next;
};
struct msg_marker : public acto::msg_t {
size_t value;
};
public:
Node() {
Handler< msg_init >(&Node::doInit);
Handler< msg_marker >(&Node::doMarker);
}
private:
void doInit(acto::actor_t& sender, const msg_init& msg) {
m_next = msg.next;
}
void doMarker(acto::actor_t& sender, const msg_marker& msg) {
msg_marker result(msg);
// -
if (result.value == STOP_VALUE)
context.send(result);
else {
result.value += 1;
m_next.send(result);
}
}
private:
acto::actor_t m_next;
};
// Desc:
class Ring : public acto::implementation_t {
public:
struct msg_init : public acto::msg_t { };
public:
Ring() {
Handler< msg_init > (&Ring::doInit);
Handler< msg_marker >(&Ring::doMarker);
}
private:
typedef Node::msg_marker msg_marker;
// -
void doMarker(acto::actor_t& sender, const msg_marker& msg) {
__int64 end;
__int64 frq;
// -
::QueryPerformanceCounter ((LARGE_INTEGER*)&end);
::QueryPerformanceFrequency((LARGE_INTEGER*)&frq);
// -
std::cout << "marker value : " << msg.value << std::endl;
std::cout << "time ticks : " << end - m_start << std::endl;
std::cout << "time seconds : " << (end - m_start) / frq << std::endl;
for (size_t i = 0; i < m_nodes.size(); i++)
acto::destroy(m_nodes[i]);
}
// -
void doInit(acto::actor_t& sender, const msg_init& msg) {
if (NODES > 0) {
m_nodes.reserve(NODES);
// 1. Создать элементы цепи
for (size_t i = 0; i < NODES; i++)
m_nodes.push_back(acto::instance_t< Node >(self));
// 2.
for (size_t i = 1; i < m_nodes.size(); i++)
setLink(m_nodes[i-1], m_nodes[i]);
// Замкнуть кольцо
setLink(m_nodes.back(), m_nodes.front());
// 3. Запустить
{
std::cout << "start passing..." << std::endl;
// -
::QueryPerformanceCounter((LARGE_INTEGER*)&m_start);
// -
Node::msg_marker marker;
marker.value = 0;
m_nodes.front().send(marker);
}
}
}
private:
void setLink(acto::actor_t& from, acto::actor_t& to) {
Node::msg_init msg;
msg.next = to;
// -
from.send(msg);
}
private:
__int64 m_start;
std::vector< acto::actor_t > m_nodes;
};
//----------------------------------------------------------------
int main()
{
std::cout << "--- start acto ---" << std::endl;
// Инициализировать библиотеку.
acto::startup();
{
acto::actor_t ring = acto::instance_t< Ring >();
// -
Ring::msg_init msg;
ring.send(msg);
// -
_getch();
}
std::cout << "--- end acto ---" << std::endl;
acto::shutdown();
// Выполнение программы закончено
std::cout << ": end" << std::endl;
_getch();
// -
return 0;
}
№ 6043 14-12-2007 05:25 |  |
Ответ на »сообщение 6038« (pepper)
___________________________
VC6.0 не оптимизирует плавающую точку в принципе. Возьмите современный интеловский компилятор, получите факторы...
Спасибо, мысль понятна, от комментариев воздержусь.
№ 6042 14-12-2007 03:04 |  |
Ответ на »сообщение 6020« (Стэн)
___________________________
Кстати, я ее тестировал до более чем 1'000'000 активных объектов, и все очень даже стабильно...
Кстати, вот мне любопытно, как будет выглядеть и работать с Вашими акторами простенькая программа, в которой, скажем, сто тысяч акторов образуют кольцо и пересылают друг другу сообщения по этому кольцу. Примерно так: главная функция программы создаёт n акторов, даёт им ссылки на следующего (первому -- на второго, второму -- на третьего, ..., n-му -- на первого), затем посылает первому число ноль (int32, например), первый увеличивает его на единичку и отсылает второму и т.д. до тех пор, пока следующий актор не обнаружит, что это сообщение содержит число m (ну, например, миллион). Затем это число отсылается главной функции, которая его просто печатает...
Вот любопытно, насколько просто или сложно будет это сделать, как стабильно это будет работать, и сколько времени будет потрачено на пересылку этих сообщений, как будет замедляться программа в зависимости от числа акторов сколько вообще акторов сможет максимально запуститься... В смысле, насколько легковесны Ваши акторы? ;о)
ЗЫ. Вот для ориентира код на Хаскелле: import IO
import Time
import System
import Control.Monad
import Control.Concurrent
defMsgs = 1000000 :: Int -- Дефолтные количества сообщений и потоков
defThrs = 1000 :: Int
main = do
hSetBuffering stdout NoBuffering
args <- getArgs
let (numThr, numMsg) = case map read args of
t:m:_ -> (t, m)
t:_ -> (t, defMsgs)
_ -> (defThrs, defMsgs)
putStr $ show numThr ++ ", " ++ show numMsg ++ " Timings: "
t1 <- getClockTime
-- Создаём каналы связи для каждого потока
(mainCh:thrChs) <- forM [0..numThr] $ \_ -> newChan
t2 <- getClockTime; putStr $ showTimeDif t2 t1 -- Время на создание каналов
-- Запускаем потоки, указав им каналы: свой и следующего потока
thrs <- forM [0..numThr-1] $ \i -> do
forkIO $ newThr numMsg -- Сколько всего будет пересылок
mainCh -- Куда отправить результат
(thrChs !! i) -- Откуда принимать сообщение
(thrChs !! if i == numThr-1 then 0 else i+1) -- и куда его переслать
t3 <- getClockTime; putStr $ " " ++ showTimeDif t3 t2 ++ " " -- Время на запуск потоков
-- Запустим цепочку пересылок сообщений
writeChan (thrChs !! 0) 0
-- Ждём конечного результата
putStr . show =<< readChan mainCh
t4 <- getClockTime -- время на пересылку сообщений и общее время работы
putStrLn $ " " ++ showTimeDif t4 t3 ++ " Total time: " ++ showTimeDif t4 t1
newThr max mainCh myCh nextCh = do
num <- readChan myCh
if num == max then do writeChan mainCh num
else do writeChan nextCh $! num + 1
newThr max mainCh myCh nextCh
showTimeDif ft st = show(tdHour td) ++ ":" ++ show(tdMin td) ++ ":"
++ show nsecs ++ "." ++ snms
where
td = ft `diffClockTimes` st
secs = tdSec td
ms = tdPicosec td `div` 1000000000
(nsecs, nms) = if ms < 0 then (secs - 1, ms + 1000) else (secs, ms)
snms = reverse $ take 3 $ (reverse $ show nms) ++ "000"
№ 6041 14-12-2007 02:25 |  |
Ответ на »сообщение 6015« (Илья Ермаков)
___________________________
Не сочтите за серость и дремучий провинциализм... Но что це такое буде - SVG?
SVG -- довольно серьёзная вещь, сейчас она широко популярна в узких кругах. С помощью SVG предлагается, например, делать веб-приложения, заменив им всякие там проприетарные Macromedia Flash, поддержка SVG есть во всех нормальных браузерах, в отличии от Flash...
Не знаю как Вам, а мне нравится вот эта апплетка на SVG: http://www.croczilla.com/svg/samples/svgtetris/svgtetris.svg
И ещё куча разных примерчиков: http://www.croczilla.com/svg/samples/
№ 6040 14-12-2007 01:59 |  |
Ответ на »сообщение 6028« (Илья Ермаков)
___________________________
>>> Плюс выйти на распределённость этого механизма в С++ очень трудно, если вообще возможно.
Вообще-то, выйти можно, но там действительно немного другой механизм и сложность чуть больше:
http://sobjectizer.sourceforge.net/
Однако лично у меня есть очень большие сомнения относительно необходимости выводить именно этот механизм на уровень распределенности. Часто приходится сталкиваться, например, у меня в блоге писали:
http://stanonwork.blogspot.com/2007/07/blog-post_18.html#c1516085987407081387
с тем, что раз модель актеров, то какая разница локально, распределено?! Сообщение отправили, сообщение получили... Но разница есть и весьма большая. Мы ведь не ожидаем, что посреди выполнения какой-то функции отключится модуль памяти, либо сгорит процессор. А если и ожидаем, то единственное, что обычно делаем - старый компьютер выбрасываем, новый покупаем, а программу перезапускаем. В сети все по-другому: вполне нормально, что часть компьютеров выйдет из строя, однако наша система должна продолжать работать. В результате, все это порожадет совершенно разные требования к программам, которые работают распределено, и программам, которые работают просто параллельно...
>>> Так вот над каким вопросом я думаю - почему тогда не оставить блокирующую посылку сообщения с ожиданием ответа на уровне примитивов? (в эрланге-то ясно почему, ибо язык функциональный, состояния исключены). С другой стороны, это усложнит диспетчерирование потоков, т.к. сейчаc в своей библиотеке между посылкой запроса и приходом ответа Вы можете перекинуть поток на "оживление" любого другого актёра, а в этом случае контекст потока нужно сначала сохранить, потом опять восстановить... Либо вообще не трогать этот поток, но тогда количество одновременно оживляемых клиент-серверных актёров резко снизится...
Все зависит от того, какой результат хочется получить. Мне надо было получить систему с множеством легких активностей, работающую поверх тяжелых потоков ОС. Поэтому поток трогать в любом случае надо. Если у Вас их не так много, то можно об этом подумать...
В вопросе о том, как переключать - можно рассмотреть два варианта: 1) сохранять контекст 2) с помощью предкомпиляции разбивать один логический метод на несколько физических - до блокировки, и после блокировки.
Ну и, - нужно ли оставить блокировку? Да, для некоторых задач это бы облегчило написание кода, но это, как мне думается, надо аккуратно заворачивать в высокоуровневое представление, а потом транслировать в примитивы runtime'а, в котором этих блокировок нет из-за требования обеспечить множество легких активностей.
Посмотрите вот эту ссылку:
www.stanford.edu/class/cs240/readings/capriccio-sosp-2003.pdf
Также получается многоуровневое решение, с асинхронным API внизу.
№ 6039 14-12-2007 01:26 |  |
Ответ на »сообщение 6035« (Qr)
___________________________
Ответ на »сообщение 6009« (Илья Ермаков)
Ну вот хоть какое-то число (+/-10%) названо, правда что оно означает пока все еще загадка.
Если речь o сравнении xds vs Visual C++, то xds может проигрывать процентов 20-30, что действительно очень неплохо. Если же сравнивать ББ и Visual C++, то ББ будет проигрывать уже ФАКТОР 2-3. Алгоритмикой будем исправлять? Или может все-же сначала стоит действительно довести ББ до ума в смысле производительности, а народ потом и сам потянется?
Народ и так тянется. А чем больше будет промышленных применений, тем скорее можно надеяться, что Excelsior сделают из XDS оптимизатор для ББ. А ваять оптимизатор на коленках неизвестно для чего - знаете, "не зная броду...".
По поводу "проигрывать процентов 20-30" - я ж говорю, зависит от версии. Если освежить оптимизатор и осовременить систему команд, то будет ровно наоборот, как уже было когда-то в 90-х, когда с XDS не мог тягаться ни один С-компилятор. Это ж теоретически обосновано - язык с регулярным синтаксисом и отсутствием неструктурных операторов оптимизируется гораздо лучше (см. Ахо, Сети, Ульман "Компиляторы"). А в С-шных программах break на break-е - а каждый break, как и goto - это палка в колёса оптимизатору.
А производительность - штука весьма тонкая. Например, на неё приличное влияние (в интеграле, по общей "реактивности" системы) оказывает архитектура. Есть много примеров, когда страшилки, высосанные из пальца, расходятся с практикой (например, теоретически микроядро должно ощутимо замедлять работу ОС, а бывает, что Unix, запущенный в пользовательском режиме поверх микроядра, начинает работать эффективнее - про такой случай на недавнем семинаре, кстати, рассказывал А.С. Косачев, вед.н.с. Института системного программирования РАН).
И вообще, читать Дейкстру :-)
"Возможность использования языков программирования в качестве средства общения с существующими автоматическими вычислителями, в течение долгого времени рассматривалась как их наиболее важное свойство. ... Как огорчительное следствие мы нередко обнаруживаем, что аномалии существующих вычислительных машин старательно воспроизводятся в языках программирования, прич\"ем это происходит в ущерб интеллектуальной управляемости программ, выражаемых на таком языке (как будто программирование и без этих аномалий не было уже достаточно трудным!) ... Я рассматриваю язык программирования преимущественно как средство для описания (потенциально весьма сложных) абстрактных конструкций."
№ 6038 14-12-2007 00:10 |  |
Ответ на »сообщение 6037« (info21)
___________________________
там смотреть страницу 8.
VC6.0 не оптимизирует плавающую точку в принципе. Возьмите современный интеловский компилятор, получите факторы...
№ 6037 13-12-2007 23:32 |  |
Добавить свое сообщение
Отслеживать это обсуждение 
Дополнительная навигация: |
|