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 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
- // Only allow 2 of these tasks to run concurrently
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
- ## Fibers
27
- Virtual threads with more controlled execution.
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 thread1 = fiber.fn(function* () {
34
- console.log('Fiber 1 started');
34
+ const fetchLatch = latch.init();
35
35
 
36
- // Thread1 will be interrupted by thread2
37
- // As thread2 will end first
38
- yield cio.sleep(1000);
36
+ const task = async () => {
37
+ // Blocks until the latch is open
38
+ await latch.pause(fetchLatch);
39
39
 
40
- console.log('Fiber 1 done');
41
- })
40
+ const res = await fetch('http://example.com');
41
+ console.log('Fetch status:', res.status);
42
+ }
42
43
 
43
- const thread2 = fiber.fn(function* (thread) {
44
- console.log('Fiber 2 started');
44
+ const prepare = () => {
45
+ console.log('Run before fetch:', performance.now().toFixed(2));
46
+ }
45
47
 
46
- yield;
47
- console.log('Fiber 2 resumed');
48
+ const main = async () => {
49
+ const p = task();
50
+ await cio.sleep(500);
51
+ prepare();
48
52
 
49
- // Start thread 1 and make thread1
50
- // lifetime depends on thread2
51
- fiber.mount(fiber.start(thread1), thread);
53
+ // Allows all previously blocked tasks to run
54
+ latch.open(fetchLatch);
52
55
 
53
- console.log('Fiber 2 done');
54
- });
56
+ // Reclose the latch
57
+ // Tasks that aren't blocked yet will be blocked
58
+ latch.reset(fetchLatch);
55
59
 
56
- // Start running the thread
57
- fiber.start(thread2);
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
- ## Latch
97
- Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
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 fetchLatch = latch.init();
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
- const prepare = () => {
114
- console.log('Run before fetch:', performance.now().toFixed(2));
115
- }
116
+ // Thread1 will be interrupted by thread2
117
+ // As thread2 will end first
118
+ yield cio.sleep(1000);
116
119
 
117
- const main = async () => {
118
- const p = task();
119
- await cio.sleep(500);
120
- prepare();
120
+ console.log('Fiber 1 done');
121
+ });
121
122
 
122
- // Allows all previously blocked tasks to run
123
- latch.open(fetchLatch);
123
+ const thread2 = fiber.fn(function* (thread) {
124
+ console.log('Fiber 2 started');
124
125
 
125
- // Reclose the latch
126
- // Tasks that aren't blocked yet will be blocked
127
- latch.reset(fetchLatch);
126
+ yield;
127
+ console.log('Fiber 2 resumed');
128
128
 
129
- return p;
130
- }
129
+ // Start thread 1 and make thread1
130
+ // lifetime depends on thread2
131
+ fiber.mount(fiber.spawn(thread1), thread);
131
132
 
132
- // Run fetch after 500ms
133
- await main();
133
+ console.log('Fiber 2 done');
134
+ });
134
135
 
135
- // Run fetch after another 500ms
136
- await main();
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 start: Runtime;
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 start=(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 function*unwrap(t){return yield t}
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>) => Promise<void>;
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>) => 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.20",
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
- "./fiber": "./fiber.js",
24
- "./channel": "./channel.js",
22
+ "./fixed-queue": "./fixed-queue.js",
23
+ "./latch": "./latch.js",
25
24
  "./dropping-queue": "./dropping-queue.js",
26
- "./topic": "./topic.js",
25
+ "./channel": "./channel.js",
27
26
  ".": "./index.js",
27
+ "./topic": "./topic.js",
28
28
  "./semaphore": "./semaphore.js",
29
- "./latch": "./latch.js"
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)}};export let task=(s,f)=>{f=wrap(f);return(...a)=>f(s,...a)};
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)}};