ciorent 0.0.20 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -60
- package/fiber.d.ts +7 -1
- package/fiber.js +1 -1
- package/index.d.ts +2 -2
- package/index.js +1 -1
- package/package.json +6 -6
- package/semaphore.d.ts +0 -4
- package/semaphore.js +1 -1
package/README.md
CHANGED
@@ -6,9 +6,7 @@ Semaphore is a concurrency primitive used to control access to a common resource
|
|
6
6
|
import * as semaphore from 'ciorent/semaphore';
|
7
7
|
import * as cio from 'ciorent';
|
8
8
|
|
9
|
-
|
10
|
-
const task = semaphore.task(
|
11
|
-
semaphore.init(2),
|
9
|
+
const task = semaphore.wrap(
|
12
10
|
async (task: number) => {
|
13
11
|
for (let i = 1; i <= 5; i++) {
|
14
12
|
console.log('Task', task, 'iteration', i);
|
@@ -19,42 +17,54 @@ const task = semaphore.task(
|
|
19
17
|
}
|
20
18
|
);
|
21
19
|
|
20
|
+
// Only allow 2 task to run concurrently
|
21
|
+
const sem = semaphore.init(2);
|
22
|
+
|
22
23
|
// Try to run 6 tasks concurrently
|
23
|
-
cio.concurrent(6, task);
|
24
|
+
cio.concurrent(6, (sem, id) => task(sem, id), sem);
|
24
25
|
```
|
25
26
|
|
26
|
-
##
|
27
|
-
|
27
|
+
## Latch
|
28
|
+
Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
|
28
29
|
|
29
30
|
```ts
|
31
|
+
import * as latch from 'ciorent/latch';
|
30
32
|
import * as cio from 'ciorent';
|
31
|
-
import * as fiber from 'ciorent/fiber';
|
32
33
|
|
33
|
-
const
|
34
|
-
console.log('Fiber 1 started');
|
34
|
+
const fetchLatch = latch.init();
|
35
35
|
|
36
|
-
|
37
|
-
//
|
38
|
-
|
36
|
+
const task = async () => {
|
37
|
+
// Blocks until the latch is open
|
38
|
+
await latch.pause(fetchLatch);
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
const res = await fetch('http://example.com');
|
41
|
+
console.log('Fetch status:', res.status);
|
42
|
+
}
|
42
43
|
|
43
|
-
const
|
44
|
-
console.log('
|
44
|
+
const prepare = () => {
|
45
|
+
console.log('Run before fetch:', performance.now().toFixed(2));
|
46
|
+
}
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
+
const main = async () => {
|
49
|
+
const p = task();
|
50
|
+
await cio.sleep(500);
|
51
|
+
prepare();
|
48
52
|
|
49
|
-
//
|
50
|
-
|
51
|
-
fiber.mount(fiber.start(thread1), thread);
|
53
|
+
// Allows all previously blocked tasks to run
|
54
|
+
latch.open(fetchLatch);
|
52
55
|
|
53
|
-
|
54
|
-
|
56
|
+
// Reclose the latch
|
57
|
+
// Tasks that aren't blocked yet will be blocked
|
58
|
+
latch.reset(fetchLatch);
|
55
59
|
|
56
|
-
|
57
|
-
|
60
|
+
return p;
|
61
|
+
}
|
62
|
+
|
63
|
+
// Run fetch after 500ms
|
64
|
+
await main();
|
65
|
+
|
66
|
+
// Run fetch after another 500ms
|
67
|
+
await main();
|
58
68
|
```
|
59
69
|
|
60
70
|
## Pubsub
|
@@ -93,47 +103,38 @@ cio.concurrent(5, async (id: number) => {
|
|
93
103
|
publisher();
|
94
104
|
```
|
95
105
|
|
96
|
-
##
|
97
|
-
|
106
|
+
## Fibers
|
107
|
+
Virtual threads with more controlled execution.
|
98
108
|
|
99
109
|
```ts
|
100
|
-
import * as latch from 'ciorent/latch';
|
101
110
|
import * as cio from 'ciorent';
|
111
|
+
import * as fiber from 'ciorent/fiber';
|
102
112
|
|
103
|
-
const
|
104
|
-
|
105
|
-
const task = async () => {
|
106
|
-
// Blocks until the latch is open
|
107
|
-
await latch.pause(fetchLatch);
|
108
|
-
|
109
|
-
const res = await fetch('http://example.com');
|
110
|
-
console.log('Fetch status:', res.status);
|
111
|
-
}
|
113
|
+
const thread1 = fiber.fn(function* () {
|
114
|
+
console.log('Fiber 1 started');
|
112
115
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
+
// Thread1 will be interrupted by thread2
|
117
|
+
// As thread2 will end first
|
118
|
+
yield cio.sleep(1000);
|
116
119
|
|
117
|
-
|
118
|
-
|
119
|
-
await cio.sleep(500);
|
120
|
-
prepare();
|
120
|
+
console.log('Fiber 1 done');
|
121
|
+
});
|
121
122
|
|
122
|
-
|
123
|
-
|
123
|
+
const thread2 = fiber.fn(function* (thread) {
|
124
|
+
console.log('Fiber 2 started');
|
124
125
|
|
125
|
-
|
126
|
-
|
127
|
-
latch.reset(fetchLatch);
|
126
|
+
yield;
|
127
|
+
console.log('Fiber 2 resumed');
|
128
128
|
|
129
|
-
|
130
|
-
|
129
|
+
// Start thread 1 and make thread1
|
130
|
+
// lifetime depends on thread2
|
131
|
+
fiber.mount(fiber.spawn(thread1), thread);
|
131
132
|
|
132
|
-
|
133
|
-
|
133
|
+
console.log('Fiber 2 done');
|
134
|
+
});
|
134
135
|
|
135
|
-
//
|
136
|
-
|
136
|
+
// Start running the thread
|
137
|
+
fiber.spawn(thread2);
|
137
138
|
```
|
138
139
|
|
139
140
|
## Channel
|
@@ -183,20 +184,23 @@ import * as cio from 'ciorent';
|
|
183
184
|
// Expensive sync task
|
184
185
|
const task1 = async () => {
|
185
186
|
let x = 0;
|
186
|
-
for (let i = 0; i < (Math.random() + 15) * 1e7; i++) {
|
187
|
-
// Frequent pausing
|
188
|
-
if (i % 2e6 === 0)
|
189
|
-
await cio.pause;
|
190
187
|
|
188
|
+
// Pause to let task2 to run
|
189
|
+
await cio.pause;
|
190
|
+
|
191
|
+
for (let i = 0; i < (Math.random() + 15) * 1e6; i++)
|
191
192
|
x += Math.random() * 32 + i * Math.round(Math.random() * 16);
|
192
|
-
|
193
|
+
|
193
194
|
console.log('Finish task 1:', x);
|
194
195
|
};
|
195
196
|
|
196
197
|
// Short async task
|
197
198
|
const task2 = async () => {
|
198
199
|
console.log('Fetch start', performance.now().toFixed(2) + 'ms');
|
200
|
+
|
201
|
+
// This will pause task2 to let task1 to continue running
|
199
202
|
const txt = await fetch('http://example.com');
|
203
|
+
|
200
204
|
console.log('Fetch status', txt.status);
|
201
205
|
};
|
202
206
|
|
package/fiber.d.ts
CHANGED
@@ -47,7 +47,7 @@ export declare const fn: <const Fn extends (thread: Thread, ...args: any[]) => G
|
|
47
47
|
* A basic fiber runtime
|
48
48
|
* @param g
|
49
49
|
*/
|
50
|
-
export declare const
|
50
|
+
export declare const spawn: Runtime;
|
51
51
|
/**
|
52
52
|
* Pause the execution of a fiber
|
53
53
|
* @param t
|
@@ -79,6 +79,12 @@ export declare const finish: <T extends Thread>(t: T) => T[1];
|
|
79
79
|
* @param parent
|
80
80
|
*/
|
81
81
|
export declare const mount: (child: Thread, parent: Thread) => void;
|
82
|
+
/**
|
83
|
+
* Control the fiber with an abort signal
|
84
|
+
* @param t
|
85
|
+
* @param signal
|
86
|
+
*/
|
87
|
+
export declare const control: (t: Thread, signal: AbortSignal) => void;
|
82
88
|
/**
|
83
89
|
* Unwrap a promise result
|
84
90
|
*/
|
package/fiber.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export let paused=(t)=>t[1]===0;export let running=(t)=>t[1]===1;export let done=(t)=>t[1]===2;let invoke=async(g,thread)=>{let t=g.next();while(!t.done){let v=await t.value;if(thread[1]===0){let r;let p=new Promise((res)=>{r=res});thread[2]=r;await p}if(thread[1]===2){thread[3].forEach(stop);return v}t=g.next(v)}thread[1]=2;thread[3].forEach(stop);return t.value};export let fn=(f)=>f;export let
|
1
|
+
export let paused=(t)=>t[1]===0;export let running=(t)=>t[1]===1;export let done=(t)=>t[1]===2;let invoke=async(g,thread)=>{let t=g.next();while(!t.done){let v=await t.value;if(thread[1]===0){let r;let p=new Promise((res)=>{r=res});thread[2]=r;await p}if(thread[1]===2){thread[3].forEach(stop);return v}t=g.next(v)}thread[1]=2;thread[3].forEach(stop);return t.value};export let fn=(f)=>f;export let spawn=(f,...args)=>{let thread=[null,1,null,[]];thread[0]=invoke(f(thread,...args),thread);return thread};export let pause=(t)=>{if(t[1]===1)t[1]=0};export let resume=(t)=>{if(t[1]===0){t[1]=1;t[2]?.()}};export let stop=(t)=>{if(t[1]===0){t[1]=2;t[2]?.()}else t[1]=2};export function*join(t){return yield t[1]}export let finish=(t)=>t[1];export let mount=(child,parent)=>{parent[3].push(child)};export let control=(t,signal)=>{signal.addEventListener("abort",()=>{stop(t)})};export function*unwrap(t){return yield t}
|
package/index.d.ts
CHANGED
@@ -26,10 +26,10 @@ export declare const sleepSync: (ms: number) => void;
|
|
26
26
|
* @param n
|
27
27
|
* @param task - The function to run
|
28
28
|
*/
|
29
|
-
export declare const sequential: (n: number, task: (id: number) => Promise<any
|
29
|
+
export declare const sequential: <const T extends any[]>(n: number, task: (...args: [...T, id: number]) => Promise<any>, ...args: T) => Promise<void>;
|
30
30
|
/**
|
31
31
|
* Spawn n tasks that runs concurrently
|
32
32
|
* @param n
|
33
33
|
* @param task - The function to run
|
34
34
|
*/
|
35
|
-
export declare const concurrent: (n: number, task: (id: number) => Promise<any
|
35
|
+
export declare const concurrent: <const T extends any[]>(n: number, task: (...args: [...T, id: number]) => Promise<any>, ...args: T) => Promise<any>;
|
package/index.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export let pause=Promise.resolve();export let sleep=globalThis.Bun?.sleep??globalThis.process?.getBuiltinModule?.("timers/promises").setTimeout??((ms)=>new Promise((res)=>{setTimeout(res,ms)}));let sharedBuf=new Int32Array(new SharedArrayBuffer(4));export let sleepSync=globalThis.Bun?.sleepSync??((ms)=>{Atomics.wait(sharedBuf,0,0,ms)});export let sequential=async(n,task)=>{for(let i=0;i<n;i++)await task(i)};export let concurrent=(n,task)=>{let arr=new Array(n);for(let i=0;i<n;i++)arr[i]=task(i);return Promise.all(arr)};
|
1
|
+
export let pause=Promise.resolve();export let sleep=globalThis.Bun?.sleep??globalThis.process?.getBuiltinModule?.("timers/promises").setTimeout??((ms)=>new Promise((res)=>{setTimeout(res,ms)}));let sharedBuf=new Int32Array(new SharedArrayBuffer(4));export let sleepSync=globalThis.Bun?.sleepSync??((ms)=>{Atomics.wait(sharedBuf,0,0,ms)});export let sequential=async(n,task,...args)=>{for(let i=0;i<n;i++)await task(...args,i)};export let concurrent=(n,task,...args)=>{let arr=new Array(n);for(let i=0;i<n;i++)arr[i]=task(...args,i);return Promise.all(arr)};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "ciorent",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.22",
|
4
4
|
"description": "A lightweight, low-overhead concurrency library",
|
5
5
|
"homepage": "https://ciorent.netlify.app",
|
6
6
|
"repository": {
|
@@ -18,14 +18,14 @@
|
|
18
18
|
"main": "./index.js",
|
19
19
|
"types": "./index.d.ts",
|
20
20
|
"exports": {
|
21
|
-
"./fixed-queue": "./fixed-queue.js",
|
22
21
|
"./sliding-queue": "./sliding-queue.js",
|
23
|
-
"./
|
24
|
-
"./
|
22
|
+
"./fixed-queue": "./fixed-queue.js",
|
23
|
+
"./latch": "./latch.js",
|
25
24
|
"./dropping-queue": "./dropping-queue.js",
|
26
|
-
"./
|
25
|
+
"./channel": "./channel.js",
|
27
26
|
".": "./index.js",
|
27
|
+
"./topic": "./topic.js",
|
28
28
|
"./semaphore": "./semaphore.js",
|
29
|
-
"./
|
29
|
+
"./fiber": "./fiber.js"
|
30
30
|
}
|
31
31
|
}
|
package/semaphore.d.ts
CHANGED
@@ -35,7 +35,3 @@ export declare const signal: (s: Semaphore) => void;
|
|
35
35
|
* Wrap a task to bind to a custom semaphore later
|
36
36
|
*/
|
37
37
|
export declare const wrap: <Args extends any[], Return extends Promise<any>>(f: (...args: Args) => Return) => ((s: Semaphore, ...a: Args) => Return);
|
38
|
-
/**
|
39
|
-
* Create a task that acquire a semaphore and release the access when it's finished
|
40
|
-
*/
|
41
|
-
export declare const task: <F extends (...args: any[]) => Promise<any>>(s: Semaphore, f: F) => F;
|
package/semaphore.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
import{pause as resolvedPromise}from"./index.js";export let init=(n)=>{let root=[null,null];return[n,root,root]};export let pause=(s)=>{s[0]--;if(s[0]<0){let r;let p=new Promise((res)=>{r=res});s[1]=s[1][1]=[r,null];return p}return resolvedPromise};export let signal=(s)=>{if(s[0]<0)(s[2]=s[2][1])[0]();s[0]++};export let wrap=(f)=>async(s,...a)=>{s[0]--;if(s[0]<0){let r;let p=new Promise((res)=>{r=res});s[1]=s[1][1]=[r,null];await p}try{return await f(...a)}finally{signal(s)}};
|
1
|
+
import{pause as resolvedPromise}from"./index.js";export let init=(n)=>{let root=[null,null];return[n,root,root]};export let pause=(s)=>{s[0]--;if(s[0]<0){let r;let p=new Promise((res)=>{r=res});s[1]=s[1][1]=[r,null];return p}return resolvedPromise};export let signal=(s)=>{if(s[0]<0)(s[2]=s[2][1])[0]();s[0]++};export let wrap=(f)=>async(s,...a)=>{s[0]--;if(s[0]<0){let r;let p=new Promise((res)=>{r=res});s[1]=s[1][1]=[r,null];await p}try{return await f(...a)}finally{signal(s)}};
|