Информация об изменениях

Сообщение Re[25]: Mногопоточность: C++ vs Erlang vs другие от 13.06.2015 10:50

Изменено 13.06.2015 10:52 Evgeny.Panasyuk

Здравствуйте, vdimas, Вы писали:

EP>>Никакое не ЧТД

EP>>Что мешает вот это:
EP>>
EP>>future<void> coroutine() ...
Преобразовать вот в это:

EP>>
EP>>struct coroutine : asio::coroutine ...
EP>>
?

V>То, что future<void> — это value-type, который владеет через shared над future_shared_state.

И как это мешает?

V>>>Так вот, если уши торчат, как в твоём примере, то нафига это тянуть в стандарт?

EP>>Я не предлагаю в стандарт тянуть эмуляцию на макросах. Ещё раз, я показываю как оно может быть устроенно внутри.
V>Я прекрасно понимаю, как оно устроено изнутри. Но я, хоть убей, не могу понять, как ты собрался реализовать свои желания с т.з. системы типов C++?
V>Вот у нас есть тип std::future, который устроен примерно так:
V>
V>template<class T>
V>class future {
V>...
V>  shared_ptr<shared_state> shared_state_;
V>}
V>

V>Т.е. внутри него всего одно поле и sizeof(future<>) скорее всего совпадет с sizeof(shared_state_).
V>Где ты предлагаешь разместить аналог своего asio::coroutine в future<>?

Там же где и обычное обычное замыкание-продолжение.
Абстрагируйся от asio::coroutine, представь простое замыкание-продолжение. Например у нас вместо:
future<int> sum()
{
    int x = await foo();
    int y = await bar();
    return x + y;
}
есть ручное нарезание на продолжения:
future<int> sum()
{
    return foo().then([](int x)
    {
        return bar().then([=](int y)
        {
            return x + y;
        });
    });
}
Где по-твоему здесь размещаются эти продолжения? И почему stackless корутина должна размещаться в каком-то другом месте?

V>Я бы его разместил в объекте-наследнике того самого shared_state, который, в свою очередь, создаётся на куче.


А здесь можно вообще не менять ни сам future, ни лезть в его внутренности (типа наследования от shared_state). Потому что используем ли мы обычные продолжения, или объект-автомат (ручной или сгенерированный stackless coroutine) — это совершенно ортогонально тому где мы их размещаем.

V>Другое дело:

V>
V>iterator<T> generate() resumable {
V>  yield return 1;
V>  yield return 2;
V>};
V>

V>Т.к. тип iterator<> еще не специфирован, вполне возможно, что у него будет некое зарезервированное поле, в котором можно поместить целочисленную переменную — состояние автомата-корутины.

Ты понимаешь что над корутинами из Boost.Asio можно сделать обёртку-итератор, в котором полностью будет хранится вся корутина? Или показать пример?

V>Если твоя легковесная корутина будет содержать в себе другие корутины, то нужно эмулировать стек для их правильного обхода. И тут уже, извини, но без выделения памяти в куче — никак.


Зачем? Вложенная корутина будет просто полем объекта внешней корутины
Вот пример, в нём нет никаких аллокаций в куче (Live Demo on Coliru):
struct first_coroutine : asio::coroutine
{
    unsigned i;

    int operator()()
    {
        reenter(*this)
        {
            for(i = 0; ; ++i)
                yield return i;
        }
    };
};

struct second_coroutine : asio::coroutine
{
    first_coroutine inner;

    int operator()()
    {
        reenter(*this)
        {
            while(true)
                yield return [b] inner()[/b] * 2;
        }
    };
};

int main()
{
    second_coroutine c;
    for(int i=0; i!=5; ++i)
        cout << c() << endl;
}
Вывод:
0
2
4
6
8
Re[25]: Mногопоточность: C++ vs Erlang vs другие
Здравствуйте, vdimas, Вы писали:

EP>>Никакое не ЧТД

EP>>Что мешает вот это:
EP>>
EP>>future<void> coroutine() ...
Преобразовать вот в это:

EP>>
EP>>struct coroutine : asio::coroutine ...
EP>>
?

V>То, что future<void> — это value-type, который владеет через shared над future_shared_state.

И как это мешает?

V>>>Так вот, если уши торчат, как в твоём примере, то нафига это тянуть в стандарт?

EP>>Я не предлагаю в стандарт тянуть эмуляцию на макросах. Ещё раз, я показываю как оно может быть устроенно внутри.
V>Я прекрасно понимаю, как оно устроено изнутри. Но я, хоть убей, не могу понять, как ты собрался реализовать свои желания с т.з. системы типов C++?
V>Вот у нас есть тип std::future, который устроен примерно так:
V>
V>template<class T>
V>class future {
V>...
V>  shared_ptr<shared_state> shared_state_;
V>}
V>

V>Т.е. внутри него всего одно поле и sizeof(future<>) скорее всего совпадет с sizeof(shared_state_).
V>Где ты предлагаешь разместить аналог своего asio::coroutine в future<>?

Там же где и обычное обычное замыкание-продолжение.
Абстрагируйся от asio::coroutine, представь простое замыкание-продолжение. Например у нас вместо:
future<int> sum()
{
    int x = await foo();
    int y = await bar();
    return x + y;
}
есть ручное нарезание на продолжения:
future<int> sum()
{
    return foo().then([](int x)
    {
        return bar().then([=](int y)
        {
            return x + y;
        });
    });
}
Где по-твоему здесь размещаются эти продолжения? И почему stackless корутина должна размещаться в каком-то другом месте?

V>Я бы его разместил в объекте-наследнике того самого shared_state, который, в свою очередь, создаётся на куче.


А здесь можно вообще не менять ни сам future, ни лезть в его внутренности (типа наследования от shared_state). Потому что используем ли мы обычные продолжения, или объект-автомат (ручной или сгенерированный stackless coroutine) — это совершенно ортогонально тому где мы их размещаем.

V>Другое дело:

V>
V>iterator<T> generate() resumable {
V>  yield return 1;
V>  yield return 2;
V>};
V>

V>Т.к. тип iterator<> еще не специфирован, вполне возможно, что у него будет некое зарезервированное поле, в котором можно поместить целочисленную переменную — состояние автомата-корутины.

Ты понимаешь что над корутинами из Boost.Asio можно сделать обёртку-итератор, в котором полностью будет хранится вся корутина? Или показать пример?

V>Если твоя легковесная корутина будет содержать в себе другие корутины, то нужно эмулировать стек для их правильного обхода. И тут уже, извини, но без выделения памяти в куче — никак.


Зачем? Вложенная корутина будет просто полем объекта внешней корутины
Вот пример, в нём нет никаких аллокаций в куче (Live Demo on Coliru):
struct first_coroutine : asio::coroutine
{
    unsigned i;

    int operator()()
    {
        reenter(*this)
        {
            for(i = 0; ; ++i)
                yield return i;
        }
    };
};

struct second_coroutine : asio::coroutine
{
    first_coroutine inner;

    int operator()()
    {
        reenter(*this)
        {
            while(true)
                yield return inner() * 2;
        }
    };
};

int main()
{
    second_coroutine c;
    for(int i=0; i!=5; ++i)
        cout << c() << endl;
}
Вывод:
0
2
4
6
8