Pull to refresh
-1
0
cybergrind @cybergrind

User

Send message
Вопросы получения сообщений касаются исключительно логики queue, т.е.
— хотим что бы был round robin — консьюмеры должны слушать одну очередь на всех
— хотим что бы каждый получил сообщене — консьюмеры должны слушать разные очереди

Вопросы роутинга находятся на стыке queue and exchange, при этом тип exchange — скорее способ задавать различные способы адресации.

И последнее — из коробки можно подписать одну очередь несколькими биндингами, которые могут иметь разные типы exchange and routing keys, а можно — слушать несколько очередей (тут есть разница между «подписываться» и «слушать»), соответственно выбор правильной стратегии (много очередей мало биндингов или наоборот) зависит от задачи (ну или уже имеющегося хозяйства)
Я наверное уже слишком много раз повторился на разный лад, но еще раз попробую высказать свою точку зрения (в последний раз в этом топике, а то мы рискуем скатиться в слишком эмоциональные обсуждения).

Что показал топик — что каналы с синхронизацией, штука не бесплатная (при одном потоке синхронизация на не нужна).
Что происходит при приведенном коде, запущенном в одном потоке?
1 кладем ch1 < — i
2 т.к. достигли максимального буффера, возвращаем управление в главный поток исполнения
3 ищем гороутину которая может что-либо сделать
4 (это будет вторая гороутина, main заблокирована на ch2) забираем сообщение из < — ch1
5 т.к. вторая гороутина блокируется на чтении — возвращаем управление в главный поток исполнения
....repeat…

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

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

а) не использовать каналы если затраты на синхронизацию и возврат управления > накладных расходов по обработке того, что отправляем в канал
б) если пункт а не прокатывает — пытаемся сделать так, что бы эти накладные расходы настолько превышали расходны на синхронизацию, что мы могли бы не заморачиваться на этот счет. тут есть тоже несколько стратегий.
б1) шлем реально «большие» — в плане затрат собщения (например массив за какое-то время)
б2) делаем буфер на основном передающем канале, но с помощью второго канала лочим гороутины относительно друг друга (когда кто-то выгребает очередь — ему никто не мешает). это уже поможет не настолько сильно, но хотя бы гороутины не начнут драться за доступ к каналам

p.s. примерно в районе 2.5к на ядро пролегает очень много ограничений в асинхронном программировании (цифра может, ясное дело, меняться в зависимости от мощности компа, у меня 2.5к была производительности твистеда на helloworld аппликейшне, да и еще что-то такое мелькало). думаю тут дело в затратах на использование сисколов при наивном подходе к использованию асинхронных примитивов и надо смотреть в strace на что уходит время, и далее думать над тюнингом системы. Но тут я могу заблуждаться, глубоко не влазил
Ну если мы все понимаем, что в этом коде не так, то может тогда не будет у людей создавать иллюзию, что go плохой язык, или GOMAXPROCS>1 плохо. Можно ведь честно сразу заявить, что данный код приведен не из реальных проблем го, а скорее про то, как в нем можно стрелять себе в ногу на ровном месте если не понимать как это работает, ведь вполне однозначно понятно, что синхронизация — штука не бесплатная, и если играть без нее — то будет быстрее (хотя разве тут это еще не всем очевидно?)

p.s. я читал код =)
p.p.s. стоит хоть немного нагрузить больше код обрабатывающий ch1, и запустить побольше гороутин — и чудесным образом все начнет ускорятся относительно одного потока.

ну и еще обидно за такие наезды на go на ровном месте
Суть в том, что тут код который не надо параллелить. Он не параллелится — тут не надо двух гороутин. если без буффера в миллион — заменяем спавн второй гороутины на вызов функции из первой (что и происходит в вашем коде при GOMAXPROCS=1), и не заморачиваемся, надо отдавать себе отчет в том, что мы делаем и почему.
И еще, в го, если правильно подойти к вопросу и подумать над тем что надо, почти всегда можно дойти до идеального ускорения в N раз (по-количеству процессов), если задача имеет такое решение.

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

а потом я понял в чем дело, и видимо на данные грабли уже наступало много людей, вот на этом видео vimeo.com/49718712 объясняют, что вы поняли неправильно, и как надо делать.

и да, данную версию кода можно сделать эквивалентной с GOMAXPROCS > 1, надо не давать второй гороутине лезть в канал до выполнения первой

вот код: gist.github.com/cybergrind/6734605
вот результаты:
1 процесс
kpi➜~/tmp» time go run tt.go [23:18:16]

Total: 0 48.514956
go run tt.go 0.29s user 0.04s system 98% cpu 0.333 total
6 процессов
kpi➜~/tmp» time go run tt.go [23:18:24]
NumCPU 6
TT 1

Total: 0 46.893547
go run tt.go 0.29s user 0.04s system 98% cpu 0.327 total
есть мнение, что очень сильно зависит от монитора

You have perfect color vision!
Your score: 0
А много маленьких, это сколько?

И разве не имеет смысл делать много таблиц, а не баз, vacuum же можно организовать per-table

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

что-то не представляю какие еще решения могут быть настолько шокирующими, что бы попадать под NDA =)
ездили и ночью, и днем, 5 км никак не потянет на 50 евро, такси в барселоне очень дешевое
import string
from collections import defaultdict


def main():
    n = 5
    s = '.-;:,/\'"?!()*\n'
    tr = string.maketrans(s, ' '*len(s))
    f = string.translate(open('pg2600.txt').read().lower(), tr)
    acc = defaultdict(int)
    for i in f.split():
        acc[i] += 1
    for k,v in acc.iteritems():
        if v == n:
            print k

main()

➜ wp time python2 test1.py > o
python2 test1.py > o 0.18s user 0.05s system 97% cpu 0.236 total
еще две мэри написаны как MARY
в двух словах, дело получается в том, что приложение на эрланге, это не просто такая же штука, как и написанное приложение на C/CPP/python/etc, но и еще довольно навороченная виртуальная машина, которая делает много работы под капотом (в С приложение делает в принципе только то, что ты ему скажешь делать)

у Льва Валкина есть хорошие статьи на тему эрланга и специализированных задач lionet.livejournal.com/84884.html и lionet.livejournal.com/88113.html
я так понимаю, у вас там довольно активно используют эрланг. собственно в рассылке есть попытки оптимизаций epoll_wait, типа erlang.org/pipermail/erlang-questions/2012-July/067871.html

но тут надо ясно себе представлять почему писалось именно так, как есть сейчас, и потом не
собственно если почитать man epoll_wait то можно увидеть, что четвертым параметром идет таймаут, в эрланге = 0, в nginx'e = 500 (в моей установке).

разница тут только в том, что в эрланге надо делать еще кучу работы, помимо того, что бы слушать сокеты, а в nginx — больше ничего делать не надо, и даже возможно можно и этот таймаут увеличить до несколько больших чисел (потеряв при этом скорость ответа, хотя на нагруженном сервере, это не важно — быстрее наберется количество эвентов, чем истечет таймаут, в общем не суть).
ну, из самого простого — nginx (натравливаем на слушающий спящий процесс, пид из netstat -lntp | grep nginx):
strace -xfp 17624
Process 17624 attached — interrupt to quit
epoll_wait(7, {}, 512, 500) = 0
epoll_wait(7, {}, 512, 500) = 0
epoll_wait(7, {}, 512, 500) = 0
epoll_wait(7, {}, 512, 500) = 0
epoll_wait(7, {}, 512, 500) = 0
epoll_wait(7, {}, 512, 500) = 0
epoll_wait(7, {}, 512, 500) = 0
epoll_wait(7, {}, 512, 500) = 0
epoll_wait(7, {}, 512, 500) = 0
epoll_wait(7, {}, 512, 500) = 0

тут конечно почище, но в целом тоже не фонтан (его то оптимизировали по сисколам), в эрланге еще таймер дергают.
ну сейчас мы говорим о несколько разных вещах. idle приложение это то, которое ничего не делает (ну типа просто erl запустили, или timer:sleep(100000), или пустой цикл гоняем)

судя по strace в данном случае — это асинхронная работа с сокетами, делается именно так, как видно в логах (там в любом случае присутствует внешний луп, что бы генерировать события), если взять любое приложение с асинхронными сокетами, на любом языке — будет точно такая же картина (возьмите приложение с boost.asio или twisted, и там будет картинка 1 в 1), с poll будет еще красивее и чаще
нет, я запускал просто с -xp (-smp disabled не порождает дочерних процессов)
но и с -fxp разницы не вижу — idle процесс не делает никаких сисколов, с smp или без него

Information

Rating
Does not participate
Location
Минск, Минская обл., Беларусь
Date of birth
Registered
Activity