issue-#156 adding Coroutines to BlackBox

Merged to the master branch

Re: issue-#156 adding Coroutines to BlackBox

Postby DGDanforth » Thu Mar 30, 2017 3:17 am

Ivan,
I completely agree with you about the need to keep platform dependent code (e.g. WinApi)
separate from the generic BlackBox framework. All such platform dependent code
should only exist in a Host subsystem.
-Doug
User avatar
DGDanforth
 
Posts: 1061
Joined: Tue Sep 17, 2013 1:16 am
Location: Palo Alto, California, USA

Re: issue-#156 adding Coroutines to BlackBox

Postby Josef Templ » Thu Mar 30, 2017 10:36 am

Robert wrote:
Ivan Denisov wrote:What if we keep this issue for BlackBox 1.8 ?
I hope not. It looks like a very interesting proposal I am keen to have available (in a stable release) quickly; even if the initial proposal does ultimately prove to be a bit immature.


Since there is no software that depends on the current Coroutines proposal it can be
refined later without much problems, I think.
It could also be marked 'experimental' or similar in the docu.
But if we don't start to distribute it, there will never be feedback and experience.

I am trying to understand Dmitry's comments. What he calls 'equal opportunities'
seems to me to be already available but there may be some details. My understanding is that
he thinks that it will not be possible for his Co_ package to use the Kernel's coroutine services
but it should be possible. This has to be clarified.
Removing the 'Transfer' procedure looks quite radical to me. This is the core of all
coroutine implementations I have ever seen. But I am not sure if I understand
his approach in full detail.

- Josef
User avatar
Josef Templ
 
Posts: 2001
Joined: Tue Sep 17, 2013 6:50 am

Re: issue-#156 adding Coroutines to BlackBox

Postby Josef Templ » Mon Apr 03, 2017 8:32 am

I have found a non-trivial bug in the Kernel's GC strategy.
Unterminated but unreferenced coroutines survived forever.
This is fixed in the latest build at http://blackboxframework.org/unstable/issue-%23156/blackbox-1.7.1-a1.834.zip.

I also added a SetStackSize procedure for experimenting with different stack sizes.

Based on the discussion with Dmitri I separated the base Coroutine features from
special coroutine patterns and introduced two abstract subclasses Task and Iterator.
This allows for easy runtime checking of the intended flow of control.
The base type Coroutine is almost unchanged except:

A new field 'parent' has been added to the Coroutine base type.
This holds the starting coroutine and is used for runtime checking the flow of control
for special patterns.

RETURN now transfers to parent, which is a much better default than before.

Additional application specific special patterns can be introduced very much like
Task and Iterator but in separate modules. Examples would be special patterns for
data flow or for simulation. This cannot be in the base module, I think, because it will be
too application specific.

I think, the current design is now well-suited as a starting point to gain
experience with.

- Josef
User avatar
Josef Templ
 
Posts: 2001
Joined: Tue Sep 17, 2013 6:50 am

Re: issue-#156 adding Coroutines to BlackBox

Postby Ivan Denisov » Mon Apr 03, 2017 3:39 pm

If I understand Dmitry correct:
- Transfer should be forbidden in not main coroutine (now this has effect of GOTO operator)
- To return control to main coroutine Yeild procedure without arguments should be used...
- we should move WinApi calls to HostCoroutines module to provide "Equal opportunities" for realizations.
Ivan Denisov
 
Posts: 1694
Joined: Tue Sep 17, 2013 12:21 am
Location: Russia

Re: issue-#156 adding Coroutines to BlackBox

Postby Josef Templ » Tue Apr 04, 2017 8:04 am

Ivan Denisov wrote:If I understand Dmitry correct:
- Transfer should be forbidden in not main coroutine (now this has effect of GOTO operator)
- To return control to main coroutine Yeild procedure without arguments should be used...
- we should move WinApi calls to HostCoroutines module to provide "Equal opportunities" for realizations.


Coroutines have been introduced as a general purpose concept many decades ago.
It does not give sense to me to redefine them into special purpose patterns that some
designer has prepared and all applications must follow the limitations or cannot use
coroutines at all in cases where the limitations are too restrictive.
The potential problems are overstated largely and with the current design it
is even possible to use special patterns (Task, Iterator) for special cases,
but without restricting the general case.

> "Equal opportunities" for realizations
I cannot understand this. I am not aware of anything that introduces inequality in the current design.
The Co_ package can use the Kernel services directly or it can use wrappers around a Coroutines.Coroutine.
If the Coroutines module can use the Kernel services why shouldn't it be possible for the
Co_ package to do the same?

- Josef
User avatar
Josef Templ
 
Posts: 2001
Joined: Tue Sep 17, 2013 6:50 am

Re: issue-#156 adding Coroutines to BlackBox

Postby luowy » Tue Apr 04, 2017 9:25 pm

I think we need some examples to measure our coroutine's efficiency
compare with other language or paltform, like node.js, dotnet
e.g thousands clients connect to server(net or files)
Is that possible at moment?
luowy
 
Posts: 201
Joined: Mon Oct 20, 2014 12:52 pm

Re: issue-#156 adding Coroutines to BlackBox

Postby Josef Templ » Wed Apr 05, 2017 7:40 am

luowy wrote:I think we need some examples to measure our coroutine's efficiency
compare with other language or paltform, like node.js, dotnet
e.g thousands clients connect to server(net or files)
Is that possible at moment?


With the current implementation what you get is the efficiency of Windows fibers
plus some procedure call and state maintenance overhead. But it is dominated
by the fiber operations. The fibers are supposed to be pretty fast. It is the fastest
you can get at the WinApi level. Fibers are handled completely in user space, i.e.
there is no context switching to the Windows kernel.

The number of coroutines that you can have at the same time is limited by the
available memory and affected by the stack size chosen.
On my machine I get about 200 coroutines with the default stack and
about 6000 coroutines with a small stack.
The limits are subtle. The min stack size sum is limited by the available swap space,
the max stack size sum is limited by the available virtual address space.
Note that fibers use dynamically growing stacks between min and max.

I don't have the time to do all the comparisons but feel free to do it.
Some comparisons have been published on the community forum,
see https://community.blackboxframework.org/viewtopic.php?f=54&t=164&start=20#p968.
It shows that BlackBox coroutines are almost as fast as XDS, which is, as I understand the posting,
using handcrafted assembly code.

- Josef
User avatar
Josef Templ
 
Posts: 2001
Joined: Tue Sep 17, 2013 6:50 am

Re: issue-#156 adding Coroutines to BlackBox

Postby Ivan Denisov » Wed Apr 05, 2017 8:32 am

I suggest to add ASSERT(current = main, 21) to Transfer.

Code: Select all
   PROCEDURE Transfer* (target: Coroutine);
   BEGIN
      ASSERT(target.state = suspended, 20); (* => target # current *)
      ASSERT(current = main, 21);
      current.state := suspended;
      target.source := current;
      target.state := running;
      current := target;
      Kernel.TransferCoroutine(target.impl)
   END Transfer;

   PROCEDURE (this: Iterator) Yield*, NEW;
   BEGIN
      ASSERT(this.parent.state = suspended, 20);
      current.state := suspended;
      this.parent.source := current;
      this.parent.state := running;
      current := this.parent;
      Kernel.TransferCoroutine(this.parent.impl);
      ASSERT(this.source = this.parent, 80)
   END Yield;


The Iterator example can use Iterator pattern.
Code: Select all
   TYPE
      Iterator = POINTER TO RECORD (Coroutines.Iterator)
         next: INTEGER
      END;
   
   PROCEDURE (this: Iterator) Run;
      VAR i: INTEGER;
   BEGIN
      StdLog.String("BEGIN Iterator"); StdLog.Ln;
      FOR i := 0 TO 9 DO
         this.next := i; this.Yield
      END;
      StdLog.String("END Iterator"); StdLog.Ln
   END Run;

   PROCEDURE RunPlainIterator*;
      VAR it: Iterator;
   BEGIN
      NEW(it); Coroutines.Init(it);
      Coroutines.Transfer(it);
      WHILE it.state = Coroutines.suspended DO
         StdLog.String("next ="); StdLog.Int(it.next); StdLog.Ln;
         Coroutines.Transfer(it)
      END
   END RunPlainIterator;


Also I do not see any reason to use Task coroutines. They simply duplicate Actions.Action functions.
Can someone explain the benefits of using Coroutines.Task instead of Actions.Action, please.
Both using the same thread and gives exactly the same behavior...
Ivan Denisov
 
Posts: 1694
Joined: Tue Sep 17, 2013 12:21 am
Location: Russia

Re: issue-#156 adding Coroutines to BlackBox

Postby luowy » Wed Apr 05, 2017 9:56 am

yes, I known your fiber solution is efficient; the Co_ auther have given us a show about it;
what I want to know is the efficiency of "Task" solution base coroutine:

the other language like js, c# use 'Promise' or "Task" as base of async/await syntax sugar,
and the "Task" base coroutine switch; it have proven to be a good solution for concurrent task;

the "Task" have three state: pending,sucessed,failed,Task.Run use coroutine like this way:
Code: Select all
      repeat
         if peek() then
            res:=read(buf);
            if res = ok then task.state :=sucessed
            elsif res = error then task.state := failed
            end;
         else
            inc(time or count);
            if time or count >= max then task.state:= failed
            else
               (* Action.DoLater()  without coroutine*)
               coroutine.transfer(target); or coroutine.sleep(ms);
            end;
         end;
      until task.state IN {sucessed,failed}

the big diff from Action is "coroutine.transfer(target); or coroutine.sleep(ms); "
instead of "DoLater" which idle the cpu about 50ms, it can try another coroutine immediately,
it may resume thousands of coroutine to find the successd one or sleep() to give up this Action.Do;
so, it can be very efficient.

the important point is the "target", which traget should it chose to switch?
which coroutine should resumed on next Action.Do?

so, some suitable examples from other language need port and test,compare.
can anybody give a clue?

luowy
luowy
 
Posts: 201
Joined: Mon Oct 20, 2014 12:52 pm

Re: issue-#156 adding Coroutines to BlackBox

Postby Josef Templ » Wed Apr 05, 2017 12:45 pm

luowy wrote:yes, I known your fiber solution is efficient; the Co_ auther have given us a show about it;
what I want to know is the efficiency of "Task" solution base coroutine:

the other language like js, c# use 'Promise' or "Task" as base of async/await syntax sugar,
and the "Task" base coroutine switch; it have proven to be a good solution for concurrent task;


For background tasks the efficiency is basically limited by the so-called Windows idle period.
A Coroutines.Task uses a Services.Action for implementing the Sleep method and the
Action interval is at least 1 idle period.
In order to reduce the idle period you can run BlackBox in server mode.
But it will never go to 0 or close to it. As far as I know there is no way to
avoid the idle period.

- Josef
User avatar
Josef Templ
 
Posts: 2001
Joined: Tue Sep 17, 2013 6:50 am

PreviousNext

Return to Resolved (Features)

Who is online

Users browsing this forum: No registered users and 1 guest

cron