www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Implement async/await using Fiber

reply Yuxuan Shui <yshuiv7 gmail.com> writes:
I find this difficult because I can't passing data via 
Fiber.yield/Fiber.call pair. e.g. I want something like:

void fiberFunc() {
    //Add some file descriptor to main loop
    string y = Fiber.yield();
    writeln(y);
}

auto f = new Fiber(&fiberFunc);
f.call();
mainloop {
    if (fd_readable)
       f.call(fd.rawRead());
}

I can probably using a derived fiber class and pass the result 
via class members, but that seems clumsy and not very general. 
Any ideas?
May 19 2016
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 05/19/2016 12:57 PM, Yuxuan Shui wrote:
 I find this difficult because I can't passing data via
 Fiber.yield/Fiber.call pair. e.g. I want something like:

 void fiberFunc() {
     //Add some file descriptor to main loop
     string y = Fiber.yield();
     writeln(y);
 }

 auto f = new Fiber(&fiberFunc);
 f.call();
 mainloop {
     if (fd_readable)
        f.call(fd.rawRead());
 }

 I can probably using a derived fiber class and pass the result via class
 members, but that seems clumsy and not very general. Any ideas?
You can use a delegate that takes a ref parameter: import std.stdio; import core.thread; void fiberFunc(ref string y) { y = "produced_by_fiberFunc"; Fiber.yield(); } void main() { string data; auto f = new Fiber(() => fiberFunc(data)); f.call(); writefln("Writing in main: %s", data); } Prints: Writing in main: produced_by_fiberFunc Also see std.concurrency.Generator. Both methods appear here: http://ddili.org/ders/d.en/fibers.html Ali
May 19 2016
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 05/19/2016 04:42 PM, Ali Çehreli wrote:

 You can use a delegate that takes a ref parameter:
Correction: You can use a delegate that calls a function that takes a ref parameter. Ali
May 19 2016
prev sibling parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 19 May 2016 at 23:42:03 UTC, Ali Çehreli wrote:
 On 05/19/2016 12:57 PM, Yuxuan Shui wrote:
[...]
You can use a delegate that takes a ref parameter: import std.stdio; import core.thread; void fiberFunc(ref string y) { y = "produced_by_fiberFunc"; Fiber.yield(); } void main() { string data; auto f = new Fiber(() => fiberFunc(data)); f.call(); writefln("Writing in main: %s", data); } Prints: Writing in main: produced_by_fiberFunc Also see std.concurrency.Generator. Both methods appear here: http://ddili.org/ders/d.en/fibers.html Ali
Hmm... This could work. But I'm not satisfied with this solution. What if I have multiple yield sites in the fiber, and each have different return types? Maybe I should use a Variant?
May 19 2016
parent reply Jacob Carlborg <doob me.com> writes:
On 2016-05-20 04:14, Yuxuan Shui wrote:

 Hmm... This could work. But I'm not satisfied with this solution. What
 if I have multiple yield sites in the fiber, and each have different
 return types?

 Maybe I should use a Variant?
I think you can view "yield" as a form of "return". If you cannot return different types from a function (without it being a template) it would be weird if you could yield different types. -- /Jacob Carlborg
May 19 2016
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Friday, 20 May 2016 at 06:40:42 UTC, Jacob Carlborg wrote:
 On 2016-05-20 04:14, Yuxuan Shui wrote:

 Hmm... This could work. But I'm not satisfied with this 
 solution. What
 if I have multiple yield sites in the fiber, and each have 
 different
 return types?

 Maybe I should use a Variant?
I think you can view "yield" as a form of "return". If you cannot return different types from a function (without it being a template) it would be weird if you could yield different types.
But this is yield as in coroutine, not yield as in generators. Those yields doesn't return value to the caller of the fiber. Let's have an example: void func() { string a = wait_for_user_input(); int b = wait_for_user_to_click_a_button(); } Those two wait()s could use yield internally to transfer execution back to the caller and wait for input. But it's difficult with current dlang fiber because there's no (elegant) way to pass data (preferably with different types) while transferring executing to/from fibers.
May 20 2016
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 05/20/2016 12:56 PM, Yuxuan Shui wrote:
 On Friday, 20 May 2016 at 06:40:42 UTC, Jacob Carlborg wrote:
 On 2016-05-20 04:14, Yuxuan Shui wrote:

 Hmm... This could work. But I'm not satisfied with this solution. What
 if I have multiple yield sites in the fiber, and each have different
 return types?

 Maybe I should use a Variant?
I think you can view "yield" as a form of "return". If you cannot return different types from a function (without it being a template) it would be weird if you could yield different types.
But this is yield as in coroutine, not yield as in generators. Those yields doesn't return value to the caller of the fiber. Let's have an example: void func() { string a = wait_for_user_input(); int b = wait_for_user_to_click_a_button(); } Those two wait()s could use yield internally to transfer execution back to the caller and wait for input. But it's difficult with current dlang fiber because there's no (elegant) way to pass data (preferably with different types) while transferring executing to/from fibers.
Agreed. Fibers are not a language construct. One has to do what std.concurrency.Generator does internally. In this case, we need another layer of function calls. (I could have used Generator below and I could avoid creating a fiber for each call by moving the fibers to module-scope.) import core.thread; void input_fiber(ref string input) { while (true) { input = "hello"; Fiber.yield(); } } string wait_for_user_input() { string input; auto f = new Fiber(() => input_fiber(input)); f.call(); return input; } void click_fiber(ref int button) { while (true) { button = 42; Fiber.yield(); } } int wait_for_user_to_click_a_button() { int button; auto f = new Fiber(() => click_fiber(button)); f.call(); return button; } void func() { foreach (i; 0 .. 10) { string a = wait_for_user_input(); assert(a == "hello"); int b = wait_for_user_to_click_a_button(); assert(b == 42); } } void main() { func(); } Ali
May 20 2016