Fibers Proposal (Need a chempion)

Pausable stackful coroutines (fibers) give ability to write simple but responsive and concurrent code.

It can be used for:

  • Automatic pause long task every 16 ms to ensure 60fps.
  • Concurrent execution of different tasks (not serial).
  • Abort incomplete task (with subtasks) as reaction on event.
  • Write simple (synchronous) code.
  • Improve performance because synchronous code can be better optimized by JIT.
  • Call synchronous API (like Array:reduce) without loosing of concurrency.

API

// Fiber - lightweight thread, that has separate call stack.
// Multiple fibers concurrently executes in one system thread.
declare class Fiber< Result > extends Promise< Result > {

	// Fiber that are executing now.
	static current : Fiber< any > | null

	// Freezes current fiber until promise will be resolved.
	// After, resumes fiber and returns result or rethrows an exception if promise is rejected.
	// Throws NotInFiberError if called outside any fiber.
	static wait< Result >( promise : PromiseLike< Result > ) : Result

	// Executes function in separate fiber
	static run( task : ()=> Result ) : Fiber< Result >

	// Abort execution.
	// Do nothing if is already completed.
	abort : ()=> void

}

Other Languages

  • Greenlets in Python
  • Goroutines in Go
  • Fibers in D
  • Virtual Thread in Loom in JVM

Links

More info: JS Proposal: Fibers.md ยท GitHub

1 Like

You say "fibers concurrently executes in one system thread", yet JavaScript does not have threads. It has agents and two agents do only have limited access to shared memory (e.g. typed arrays). As such a lot of synchronization issues that parallel / preemptive multitasking have are avoided. How does your "fiber proposal" avoid that, or does it break JavaScript's runtime model?

Also both "Automatic pause long task every 16 ms to ensure 60fps." and "Abort incomplete task (with subtasks) as reaction on event." can both be achieved with generator functions (as long as the generator cooperates by yielding very often). Which benefit does this proposal have over generators?

If it helps, agents correspond roughly one to one with threads in practice*, and so while it is an abstraction, it's a pretty small abstraction that exists purely to formalize a few necessary specifics on synchronization and such.

* This of course doesn't hold everywhere - embedded is a growing exception here. At the high end like with the Pi, you do have true multithreading, but at the mid range like the Tessel it's often partially faked and at the low end with XS, you don't have threads at all.

It's cooperative multitasking. So synchronization isn't required.
Generators are slow and requires all functions higher up the stack to also be generators. Read about red-blue problen in links section.

No, generators do not require all functions higher up to be generator functions. You can call a generator function inside a regular function, the same applies to async functions. I also disagree with the whole premise of "What color is your function?" cause it proposes "threading" as an alternative without mentioning the whole zoo of synchronization issues that comes with it. Also it was written before async functions and generator functions became common in JavaScript. Engines can choose different internal representations of their environment record and they usually also do, so the whole "multiple callstacks are faster" is way too simplified to be meaningful. You say "It's cooperative multitasking", then what's the difference to async functions / generators / mutiple agents (aka. Webworkers / NodeJS processes) ? Also your claim "generators are slow" needs to be backed by data.

Also apart from synchronization, there is also currently the run to completion guarantee, which FIbers would break. Take e.g.

const getCounter = ((count) => () => count++)(0);

function task() {
  const before = getCounter();
  doStuff();
  const after = getCounter();
  assert(before === after - 1); // Currently this is _guaranteed_ to be true
}

task();
task();

If a Fiber.wait(...) would be added somewhere in doStuff this would break. So would millions of other lines of code.

it's requited to free main thread.

Cooperative multitasking don't have synchronization problem.

Generators can't be gracefuly optimized because real call stack isn't deterministic except some corner cases.

It's fundamental properties of this abstractions.

You can found some benchmark here.

And about fibers: Fiber (computer science) - Wikipedia

With generators and async functions you don't have guarantee too. It's not a problem in general.