ping pong

Nov. 20th, 2015 05:17 pm
thedeemon: (office)
[personal profile] thedeemon
Впервые дошли руки поиграться с файберами/корутинами. Кроме меня в игре два игрока: каждый из них ловит мяч (целое число), прибавляет к нему единицу и посылает другому игроку. Если число доросло до 100 000, посылает его главному треду и завершается. Главная ф-я создает двух игроков, знакомит друг с другом, запускает мяч и ждет пока оба не пришлют свои результаты. Показанный ниже код, в зависимости от (не)переданного аргумента командной строки, устраивает такую игру либо с игроками в отдельных параллельных тредах ОС, либо в разных корутинах в пределах одного треда.


import std.stdio, core.thread, std.concurrency, std.datetime;

void player(string name) {
    Tid other = receiveOnly!Tid;
    while(true) {
        int v = receiveOnly!int;
        other.send(v+1);        
        if (v >= 100000) { ownerTid.send(v); return; }
        yield();
    }
}

void main(string[] argv) {
    bool useFibers = argv.length > 1;
    if (useFibers) scheduler = new FiberScheduler;
    else           scheduler = new ThreadScheduler;

    StopWatch sw;
    sw.start();
    scheduler.start({
        auto p1 = spawn(&player, "Anne"); 
        auto p2 = spawn(&player, "Bob");
        p1.send(p2); // meet each other
        p2.send(p1);
        p1.send(1);  // send the ball  
        int n = 0;
        while(n<2) { //wait for them to finish
            if (useFibers) {
                receiveTimeout(0.msecs, (int v) { writeln(v); n++; });
                yield();
            } else {
                receiveOnly!int.writeln; n++;
            }            
        }
    });
    sw.stop();
    writeln("time: ", sw.peek.msecs, " ms");
}



На моем ноуте вариант с тредами ОС работает ~520 мс, а вариант с корутинами - 137 мс. При этом код фактически один и тот же, и, как я понимаю, реализация мэйлбоксов у них одна - т.е. в варианте с корутинами имеют место ненужные блокировки, можно было бы быстрее. Чуть разный код получился у ждущего треда - в одном случае идет блокирующее ожидание сообщения, в другом - неблокирующее + переключение. Но сам факт, что можно легко выбирать между разными скедулерами или задействовать свой, гибридный, доставляет. Было бы занятно сравнить времена и реализации с другими языками.

Upd: версия на Go отрабатывает за 35 мс.

Upd2: ее аналог на D (с самодельными типизированными каналами вместо универсальных мэйлбоксов и только корутинами) работает 24 мс.

Date: 2015-11-21 04:59 pm (UTC)
From: [identity profile] sassa-nf.livejournal.com
"вариант с тредами ОС работает ~520 мс"

Но это же сильно зависит от задачи.

Например, треды - они что, шаред мемори или нет? Если шаред мемори, то включить спин - и будет как с корутинами. А если не шаред мемори, то у нас происходит сериализация, IPC и прочий мрак (и опять, если бы как-то спин включить, чтобы не слезать с ядра, пока ответ ждёшь).

Date: 2015-11-22 05:20 am (UTC)
From: [identity profile] thedeemon.livejournal.com
Да, верно, вариантов масса возможна.
Это я просто что первое под руку попалось в стандартной библиотеке взял. Можно будет потом со спинлоками попробовать.

Date: 2015-11-22 09:02 am (UTC)
From: [identity profile] sassa-nf.livejournal.com
я все равно вижу смысл - тут же дело не только в скорости (в реальных задачах спинлок может быть неприменим - слишком много ЦПУ жрет), но и в интерфейсе. Я просто объясняю разницу в скорости в этом тривиальном примере.

Profile

thedeemon: (Default)
Dmitry Popov

December 2025

S M T W T F S
 12 3456
789101112 13
14151617181920
21222324252627
28293031   

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 30th, 2026 06:30 pm
Powered by Dreamwidth Studios