Home
Objective Caml
ocaml@conference.jabber.ru
Среда, 5 августа 2009< ^ >
f[x] установил(а) тему: Камль -- http://caml.inria.fr | Логи -- http://chatlogs.jabber.ru/ocaml@conference.jabber.ru/ | Верблюды грязи не боятся!
Конфигурация комнаты

GMT+4
[02:11:46] sevenov вышел(а) из комнаты
[02:12:11] sevenov вошёл(а) в комнату
[02:16:51] abiogenesis вышел(а) из комнаты
[08:12:38] daapp вошёл(а) в комнату
[08:24:26] gds вышел(а) из комнаты
[09:02:19] gds вошёл(а) в комнату
[09:55:35] Typhon вошёл(а) в комнату
[10:43:28] sceptic вышел(а) из комнаты
[10:58:37] sceptic вошёл(а) в комнату
[11:30:13] gds вышел(а) из комнаты: Replaced by new connection
[11:30:14] gds вошёл(а) в комнату
[11:38:41] sevenov вышел(а) из комнаты
[11:38:45] sevenov вошёл(а) в комнату
[12:02:58] sevenov вышел(а) из комнаты: Replaced by new connection
[12:03:00] sevenov вошёл(а) в комнату
[13:27:38] sevenov вышел(а) из комнаты
[13:28:13] sevenov вошёл(а) в комнату
[13:28:39] sevenov вышел(а) из комнаты
[13:29:01] sevenov вошёл(а) в комнату
[14:28:12] <gds> "сегодня мы многое поняли". когда пишете на функторах, учитывайте: 1. ребинд типа модуля (module type A = B.A) делает несовместимыми A.t и B.A.t -- номинальная типизация, то есть. 2. чтобы при применениях функторов типы были совместимыми, нужно как в функторе объявить равенство типов:
module GcounterF (A : sig type a; end) : GathererImp with type a = A.a = struct ... end;
, так и при применении-ограничении указать:
module Gcounter : GathererImp with type a = G.a = GcounterF(struct type a = G.a; end);
хочу эту мелкую софтинку принципиально на функторах сделать, чтобы лучше их понимать.
[14:38:05] sevenov вышел(а) из комнаты
[14:38:22] sevenov вошёл(а) в комнату
[14:59:29] daapp вышел(а) из комнаты
[16:28:49] sevenov вышел(а) из комнаты
[16:29:04] sevenov вошёл(а) в комнату
[17:29:06] gds вышел(а) из комнаты
[17:52:01] gds вошёл(а) в комнату
[19:06:17] Typhon вышел(а) из комнаты
[19:45:03] gds вышел(а) из комнаты: Replaced by new connection
[19:45:04] gds вошёл(а) в комнату
[20:10:21] sceptic вышел(а) из комнаты
[20:30:44] sceptic вошёл(а) в комнату
[21:30:56] <ermine> gds: когда из библиотеки выкидывают функцию read () (для чтения из сокета, например), то как можно избавиться от зависимости от send ()?
[21:31:57] <ermine> если либла парсит входные данные и ей нужно время от времени послать ченить
[21:46:00] <gds> ermine: ниччо не понял. выкидывают -- как именно? зависимость -- какая?
[21:49:21] <ermine> gds: написала функцию, которая в качестве входных данных берет буфер (строку), ее надо кликать внутри read () где-нить в сторонке рядом с select()-подобным циклом
[21:49:54] <ermine> раньше парсер сам вызывал read() по мере надобности :)
[21:50:36] ermine продолжает страдать фигней - перебирает разные подходы к интерфейсам
[21:51:31] <ermine> а send все равно придется передавать в аргументах
[21:53:39] <ermine> ваще код неузнаваемо изменился
[21:57:49] <gds> если будет функция, которая будет получать данные от read, и её единственная цель, кроме сайд-эффектов, это запись взад, то она может возвращать строку, которую надо будет записать взад. Возможно даже [ Write of string | Close_connection ].
Иначе всё по-любому дойдёт до получения на вход некоего значения, куда нужно будет писать какой-нибудь функцией. Значение даже может иметь тип string -> result (для какого-нибудь разумного result).
[21:58:27] <gds> а расскажи, что ещё попробовала. А то скоро предстоит похожая штука, где геморно будет по-простому строить код.
[22:01:44] <gds> а сейчас у меня борьба с блокировками -- кусок кода мелкий, два независимых мутекса, с десяток мутабельных значений, с десяток функций, работающих с ними. Думал уже и про какую-нибудь статическую проверку на уровне типов, что кому можно менять.. Один хрен, вижу, придётся руками и глозамме разгребать необходимости использования блокировок в каждом конкретном случае.
(про message passing я в курсе)
[22:02:32] <ermine> gds: а как принято в event-driven programming?
[22:03:48] <gds> если брать классическое event-driven, там куча точек входа, некое состояние, и возможность вызвать функции/методы с этим состоянием и другими параметрами.
[22:04:12] <gds> ("куча" в твоём случае сводится до одной точки, которая на recv)
[22:09:42] <ermine> у меня этот ивент-дривен реализован до read(), вот думаю чо делать с send :)
[22:10:35] <ermine> я тут недавно спрашивала как делать fsm
[22:10:48] <ermine> в итоге получился event-driven с калбэками
[22:11:45] ermine - унылый быдлокодер, да
[22:13:28] <ermine> а чтобы функция в read() вернула данные для записи - не получится, ибо в входных данных может быть несколько независимых токенов, тогда та функция циклически работает
[22:14:36] <gds> так я тоже быдлокодер! окамл -- хороший быдлоязык, я щитаю. кроме того, мы с одним челом (хаскелистом) скооперировались слегка, и хотим кое-как публично показать, что и окамл, и хаскель -- оба достойны звания быдлоязыка. посмотрим, как пойдёт.
[22:15:24] <gds> с send -- что-нибудь передаётся от одного обработанного токена к следующим?
[22:17:56] <ermine> вообще сначала создается структура данных, ее как аргумент надо передавать во все функции, вызываемые из библиотеки. read () вызывает функцию парсера и сует ей эту структуру и буфер
[22:18:27] <ermine> пока что сейчас именно такая модель - я всегда мечтала оторвать от библиотеки сетевую часть
[22:18:54] <ermine> как бы мечта не похерилась из-за send
[22:19:17] <gds> структура -- это ок, а всё же, обработка токена влияет на обработку следующего токена как-либо, кроме модификации структуры?
[22:20:44] <ermine> ну структура не safe-тредная, а так - не влияет
[22:23:10] <gds> вариант: держи в структуре Buffer.t, в который пиши всё для отправки. А ещё лучше -- тривиально модифицировать Buffer, чтобы сделать из него FifoBuffer. И по памяти ок, и send'у не надо копировать все данные через Buffer.contents. Но это оптимизации, тогда как основной принцип именно Buffer.t.
[22:25:04] <ermine> ну есть Queue
[22:25:11] <ermine> чем он не фифобуффер?
[22:26:02] <ermine> а это ничо, что если селект выдал сокет пригодный для записи, send проверяет буфер, а он пуст?
[22:27:25] <ermine> Buffet.t Queueu.t если по полному именовать тип
[22:27:35] <ermine> ой
[22:27:42] <gds> буфет!11
[22:27:47] <ermine> Buffer.t Queue.t
[22:28:16] <ermine> а как избавицо от лишней работы? :)
[22:28:27] <gds> с точки зрения концепции -- очень даже он. Но на практике быстрее, когда и recv, и send видят ровно одну строку, куда и пишут, а не (в теории) кучу мелких строк, которые при recv занимают лишнюю память (каждая добавляет оверхед), а при send заставляют или много раз дёргать send, или склеивать буфера.
[22:29:06] <gds> про селект -- если на практике такое, то странно. вроде не должно.
[22:29:41] <gds> смотря от какой лишней работы. Пока бери Buffer.t, дальше будет видно, если он приживётся.
[22:30:16] <gds> или ты про буфет? :)
[22:30:59] <ermine> в селекте надо вручную добавлять в список дескрипторов интересующий евент
[22:31:10] <ermine> короче видимо это функтор
[22:31:25] <ermine> чтобы решать задачу для однопоточности и многопоточности
[22:31:54] <gds> в селекте и добавляй: видишь, что обработчик полученных данных вернул что-то в буфер -- сразу и добавляй, а в чём проблема?
[22:32:05] <ermine> ну в данном случае непонятно как без селекта обойтись
[22:32:39] <gds> если пользуешь lwt, там вроде оно всё есть.
[22:32:59] <ermine> read() можно засунуть в тупой цикл loop(), а кто будет send дергать?
[22:33:59] <ermine> это про тот случай, если в структуре держать буфер для отправки, как ты выше описал
[22:37:34] <gds> обычно критичной в чередовании recv/send является необходимость отправки всех данных до чтения следующих данных. send можно посадить в рядом стоящий цикл, и пока всё не отправит, не будет никакого recv.
[22:38:08] <ermine> мне нада асихронно
[22:39:02] <gds> асинхронное recv/send в пределах одного сокета? но зачем?
[22:39:45] <ermine> это джаббер такой асихронный протокол
[22:40:04] <gds> нельзя подождать, пока отправятся все данные?
[22:41:06] <ermine> тут получится так, что надо подождать, пока пропарсятся все данные
[22:43:48] <gds> уточни, в какой "многозадачности" работаешь: ocaml threads, lwt, select?
в случае ocaml threads -- один тред висит на send, остальные делают recv с других сокетов. в случае lwt -- читать доку надо, но, вроде бы, там поддерживается подобный фокус (внутри себя делают select). в случае select -- самостоятельно решаешь, как и что.
[22:44:27] <gds> точнее, "один тред висит на send, остальные делают recv с других сокетов" => "один тред висит на send, остальные делают recv и парсинг полученных данных с других сокетов"
[22:45:42] <ermine> многопоточность от реализации не зависит, я надеюсь, ибо нужно только read/send и мутекс на структуру
[22:46:10] <ermine> мутекс нужно чтобы два read() не конфликтовали
[22:46:53] <gds> у тебя структура общая для всех сокетов?
[22:47:38] <ermine> нет
[22:48:43] <gds> а вот реализация -- зависит от многопоточности и её конкретного выбора.
в случае ocaml threads, если не передаёшь сокет дальше текущего треда, будешь иметь максимум один recv на один сокет.
[22:50:30] <ermine> это проблема снаружи библиотеки
[22:51:15] <gds> заворачивай всё в IO-монаду, и ваще будет проблема снаружи программы.
[22:51:36] <gds> те ребята знают, как заметать сор под ковёр.
[22:51:48] <ermine> а как там send выглядит?
[22:53:40] <ermine> ну тогда делать функтор для сенда и совать его в структуру
[22:53:53] <ermine> пофиг что это будет - буфер или сам сенд
[22:54:34] <gds> не знаю деталей, да и не важно. Я к тому, что с вещами надо разбираться там, где они появляются, в целом.
мы обсуждали параллельные recv() на одном сокете, которые передают данные в библиотеку, выдающую данные взад. Ты говоришь, что хочешь какой-то мутекс на структуру данных. Так давай поговорим о том, что происходит вне библиотеки. Конкретно это сейчас и важно, если уж решать вопросы асинхронности работы по жаббер-протоколу.
[22:56:06] <gds> если всё рассматривать в пределах библиотеки, то пофиг, будь то внешний send, будь то Buffer.t.
[22:56:28] <ermine> ох
[22:59:11] ermine пока всунет в структуру сенд, до следующего быдлоозарения
[22:59:20] <ermine> gds: спасибо за рассуждения
[23:03:51] <gds> насчёт send -- главное, что it works! it will work, точнее. приличный метод.
да и вообще, надо делать как можно более тупо, а любые усложнения -- только при необходимости.
а у меня вот уж точно назревает глобальный мутекс на структуру данных, и "мну груфняво".
[23:17:19] <gds> о, а кто-нибудь юзал Thread.critical_section? По идее, если операции быстрые, без всяких операций с тредами, без ввода-вывода, то это более легковесно, по сравнению с мутексом.
[23:33:35] <ermine> хм
[23:33:47] <ermine> а ты посмотри в код, что это такое
[23:33:56] ermine не смотрела
[23:47:50] <gds> посмотрел код, успокоился, прочитал твоё в чятике, посмотрел вдобавок к otherlibs/threads ещё и otherlibs/systhreads. Хорошо что решил последовать совету полностью и обстоятельно, иначе пришлось бы переписывать нафиг: в systhreads такая штука не работает вообще.
[23:58:49] <ermine> а чем там лочится?
Powered by ejabberd Powered by Erlang Valid XHTML 1.0 Transitional Valid CSS!