Page 4 of 11

Re: issue-#156 adding Coroutines to BlackBox

Posted: Thu Mar 30, 2017 3:17 am
by DGDanforth
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

Re: issue-#156 adding Coroutines to BlackBox

Posted: Thu Mar 30, 2017 10:36 am
by Josef Templ
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

Re: issue-#156 adding Coroutines to BlackBox

Posted: Mon Apr 03, 2017 8:32 am
by Josef Templ
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/i ... 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

Re: issue-#156 adding Coroutines to BlackBox

Posted: Mon Apr 03, 2017 3:39 pm
by Ivan Denisov
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.

Re: issue-#156 adding Coroutines to BlackBox

Posted: Tue Apr 04, 2017 8:04 am
by Josef Templ
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

Re: issue-#156 adding Coroutines to BlackBox

Posted: Tue Apr 04, 2017 9:25 pm
by luowy
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?

Re: issue-#156 adding Coroutines to BlackBox

Posted: Wed Apr 05, 2017 7:40 am
by Josef Templ
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 ... rt=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

Re: issue-#156 adding Coroutines to BlackBox

Posted: Wed Apr 05, 2017 8:32 am
by Ivan Denisov
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...

Re: issue-#156 adding Coroutines to BlackBox

Posted: Wed Apr 05, 2017 9:56 am
by luowy
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

Re: issue-#156 adding Coroutines to BlackBox

Posted: Wed Apr 05, 2017 12:45 pm
by Josef Templ
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