Roman
вот очередные хипстеры эмбед какой нить и начнут на го колбасить тогда может
Мерль
Мерль
Руст попробуйте
Roman
эт кстати не только в го
Roman
http://stackoverflow.com/questions/29008127/why-are-rust-executables-so-huge
Мерль
Это какие вам либы нужны?
Мерль
Хотя да
Roman
вон в расте можно динамическую линковку включить
Roman
но тогда будешь зависить от либ
Roman
в общем все как в той задаче про два стула
Мерль
Это какие вам либы нужны?
Сейчас там основной путь "пишите своё дерьмо сами"
Roman
баш тогда уже
Roman
бери баш и ебаш
Roman
или Гарин ты под винды тоже собираешь?
Slava
коллеги, вы через чур перевозбуждены, это на вас так слово пхп подействовало?
Anonymous
не эт гарин пришел, вбросил, стер и ушел
меньше бы ты мою фамилию поминал всуе
Anonymous
и было бы вам щасте
Anonymous
если че, этот хуй фебс. будьте осторожны
Sergey
Да ладно вам, пхп вполне себе норм
Slach
всем привет, а объясните пожалуйста насколько плохо объявлять некий глобальный контекст при обработке http handlers на golang?? не middleware а именно контект в общем мне надо чтобы несколько горутин писали в один файл в append режиме и при достижении глобального (g.writed_rows % g.chunk_size) == 0 происходил flush файла закрытие дескриптора и создание друого файла (открытие в append режиме) пытаюсь сделать как то так в качестве фреймворка использую https://github.com/gocraft/web (первое что попалось на глаза когда начал гуглить golang lightweight web framework) type MyStruct struct { sync.RWMutex // дальше много полей всякие file handlers и map tsv_writer *csv.Writer tsv_file *os.File tsv_file_name string writed_rows uint chunk_size uint } а в обработчике func (g *MyStruct) Collect(rw web.ResponseWriter, req *web.Request) { } делаю как то так https://play.golang.org/p/StfrROogbk пытаюсь юзать g.Lock и g.Unlock при записи в g а у меня пока получается что в бенчмарке func Benchmark_Collect(b *testing.B) { g := NewMyStruct() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { req := NewTestRequest() rw := web.ResponseWriter(testResponseWriter{}) for pb.Next() { g.Collect(rw, &req) } }) } переименование файла и открытие закрытие пытается делаться паралелльно =( кто нибудь может меня платно проконсультировать и поревьювить мой код более дотошно?
Givi
"в общем мне надо чтобы несколько горутин писали в один файл в append режиме" создаёшь буферизированный канал, раздаёшь его горутинам-обработчикам запросов, они туда пишут данные, запускаешь одну единственную горутину, которая, пишет в файл в нужном тебе режиме, переименовывает и т.д.
Givi
в чём сложности?
Slach
там по коду есть условие что разные запросы могут менять схему записи в CSV
Givi
объяви структуру из двух полей, данные и мета, и вместо сырых данных гоняй эту структуру, в мета указывай как должны данные сохранятся.
Daniel
Вот да
Slach
проблема в том что надо "мету" менять атомарно в разных горутинах
Daniel
А?
Daniel
Это же невозможно
Slach
что невозможно??? в разных горутинах одну мапу поменять?
Daniel
Ну давайте разберемся
Daniel
Что такое атомарно
Daniel
И как это соотносится с асинхронными процессами
Slach
ок =) сейчас поясню вот есть две горутины которые запускают Collect паралельно в них на вход идет два разных экземлпяра структуры web.Request они содержат разный (но пересекующийся в части ключей) набор полей в каждой горутине Collect я хочу менять глобальную g.form_k_exists_map map[string]bool и добавлять по мере необходимости глобальный слайс сейчас юзается вот такой код for k := range req.Form { g.RLock() _, f_exists := g.form_k_exists_map[k] _, ga_exists := GA_map[k] g.RUnlock() if !f_exists && ga_exists { refresh_schema = refreshCSVShemaWithFormKey(refresh_schema, g, k) || refresh_schema } if !f_exists && !ga_exists { refresh_schema = refreshCSVShemaWithComplexKey(refresh_schema, g, k) || refresh_schema } } внутри refreshCSVShema* функций я юзаю g.Lock перед записью и g.Unlock и такое ощущение что либо забыл где то вызвать либо потому что мапа form_k_exists_map какое то не то значение содержит предлагаете этот код в отдельную горутину закинуть? и общаться с ней через буфферизированный канал?
Daniel
Так
Daniel
Давайте через час?
Daniel
Я до компа дойду
Slach
без проблем, Данил сколько стоит 2-3 часа вашего времени?
Daniel
Именно моего - 2тр в час
Daniel
Но я тут не вижу пространства для оплаты :)
Daniel
Я думаю - за 15 минут разберемся
Daniel
так, я тут
Daniel
давайте разбираться
Daniel
вот у нас функция обработки http запроса
Slach
давайте я тогда код закомичу и ссылку в личку скину у вас аккаунт на битбакет есть?
Daniel
нет, есть на github
Daniel
но можно просто секретный гист, и ссылку в личку
Daniel
но давайте погодим пока с кодом
Daniel
может быть, до него дело не дойдет
Daniel
итак
Daniel
у нас есть функция обработки http запроса
Daniel
ей на вход попадает собственно запрос и - замыканием - map[string]bool
Daniel
где тут пространство для глобального контекста?
Daniel
и атомарных его изменений
Slach
нет ей н вход попадает указатель *web.Request в котором есть req.Form как url.Values map[string][]string
Daniel
ну - да, это и есть сам запрос
Slach
сама функция Collect судя по коду фреймворка запускается в горутине
Daniel
пока все понятно
Daniel
там в Collect бесконечный цикл, или она отработала и завершилась?
Daniel
отойду опять, минут на 40
Slach
Collect должна отработать и завершиться идем дальше есть необходимость из двух горутин с Collect на вход которым подали пересекающийся набор ключей из запроса сформировать CSV файл в кототром первой строкой заголовском служит перечень полей из субд (маппинг полей формы в поля СУБД отдельная песня за рамками задачи) а дальше tab separated данные итого если нам пришло два одинаковых набора полей то CSV файл должен быть один если два разных то CSV файлов два ну вы вот посоветовали завернуть все это в отдельную горутину я сейчас пытаюсь сгородить такую конструкцию https://play.golang.org/p/avQlCmcx2h посмотрим что получится в бенмарке
Daniel
так
Daniel
попарсили form - и результат через канал в единственную горутину, и пусть уже она думает о совокупленииъ
Slach
ну вроде да, выглядит как то так =)) блин ну вот фигня какая то... теперь оно вообще даже не пытается CSV файлы писаьт func (g *GA2ClickHouse) Collect(rw web.ResponseWriter, req *web.Request) { err := req.ParseForm() if err == nil { ParseTimestamp(req) ParseUserAgent(req) ParseGeoip(req, g) go func(req *web.Request) { g.buffered_data <- BufferedData{req: req} }(req) } rw.Header().Set("Access-Control-Allow-Origin", "*") rw.Header().Set("Content-Type", "image/gif") rw.Write(GIF1px) }
nvkv
Котаны, маленький оффтопик. Если вы напишете вот так: func (g *GA2ClickHouse) Collect(rw web.ResponseWriter, req *web.Request) { ... } то уважаемый телеграм напечатаейт код моноширинным шрифтом и все будут ужасно ликовать и радоваться
nvkv
Slach
странно а у меня вот так http://take.ms/OKcR4
nvkv
потому что код без бэктиков
nvkv
обрати внимание на закорючки вокруг кода, вот такие `
Slach
ок. спасибо
Мерль
https://habrahabr.ru/company/badoo/blog/320724/
Slava
https://github.com/jbeda?tab=stars кажется это успех =)
Oleg
Признание! Поздравляю
Мерль
Slach
Народ, а подскажите пожалуйста а может канал у которого состояние closed=0 сам собой стать closed=1 ?? ну или не сам собой, а допустим после операции channel <- *pointer_to_data канал создаю буфферизированый через make закрываю через defer close(channel) а оно мне panic кидает сцуко, cannot send to closed channel
Slach
нет посылаю я не в теле функции посылаю я из другой горутины которая вызывается в теле функции как go func(req *web.Request) { g.Lock() defer g.Unlock() g.buffered_data <- *req // вот тут падает в panic }(req) читаю в еще одной горутине func (g *GA2ClickHouse) ProcessRequest() { log.Print("ProcessRequest BEGIN") for { select { case req, ok := <-g.buffered_data: if ok { // тут всякое } else { log.Println("ProcessRequest END after channel closed") return } } } } и там в ней делаю бесконечный for и return если канал закрыт
Slach
defer еще не должен по идее отработать то? или должен?