ciorent 0.0.13 → 0.0.15

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
@@ -1,5 +1,5 @@
1
1
  A lightweight, low-overhead concurrency library.
2
- # Semaphore
2
+ ## Semaphore
3
3
  Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
4
4
 
5
5
  ```ts
@@ -23,50 +23,43 @@ const task = semaphore.task(
23
23
  cio.concurrent(6, task, 4);
24
24
  ```
25
25
 
26
- # Latch
27
- Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
26
+ ## Pubsub
27
+ A fast, simple publish-subscribe API.
28
28
 
29
29
  ```ts
30
- import * as latch from 'ciorent/latch';
30
+ import * as topic from 'ciorent/topic';
31
31
  import * as cio from 'ciorent';
32
32
 
33
- const fetchLatch = latch.init();
34
-
35
- const task = async () => {
36
- // Blocks until the latch is open
37
- await latch.pause(fetchLatch);
33
+ const messages = topic.init<number>();
38
34
 
39
- const res = await fetch('http://example.com');
40
- console.log('Fetch status:', res.status);
41
- }
35
+ // A task that publish messages
36
+ const publisher = async () => {
37
+ for (let i = 0; i < 5; i++) {
38
+ await cio.sleep(100);
39
+ topic.pub(messages, i);
40
+ }
42
41
 
43
- const prepare = () => {
44
- console.log('Run before fetch:', performance.now().toFixed(2));
42
+ // Resolve all waiting promises
43
+ // And clear the value queue
44
+ topic.flush(messages);
45
45
  }
46
46
 
47
- const main = async () => {
48
- const p = task();
49
- await cio.sleep(500);
50
- prepare();
51
-
52
- // Allows all previously blocked tasks to run
53
- latch.open(fetchLatch);
54
-
55
- // Reclose the latch
56
- // Tasks that aren't blocked yet will be blocked
57
- latch.reset(fetchLatch);
58
-
59
- return p;
60
- }
47
+ // Spawn 5 tasks that recieve messages
48
+ cio.concurrent(5, async (id: number) => {
49
+ const sub = topic.sub(messages);
61
50
 
62
- // Run fetch after 500ms
63
- await main();
51
+ while (true) {
52
+ // Block until the value is sent
53
+ const x = await topic.recieve(sub);
54
+ if (x == null) break;
55
+ console.log(`Task ${id}: ${x}`);
56
+ }
57
+ });
64
58
 
65
- // Run fetch after another 500ms
66
- await main();
59
+ publisher();
67
60
  ```
68
61
 
69
- # Channel
62
+ ## Channel
70
63
  Channel is a synchronization primitive via message passing. A message may be sent over a channel, and another process is able to receive messages sent over a channel it has a reference to.
71
64
 
72
65
  ```ts
@@ -82,18 +75,15 @@ const run = async () => {
82
75
  console.log('Sent', i);
83
76
  }
84
77
 
85
- // Send the closed signal to the reciever
86
- // Or else channel.recieve will block forever
87
- channel.close(c);
78
+ // Resolve all waiting promises with `undefined`
79
+ // This is a way to tell the reciever to not listen to more data
80
+ channel.flush(c);
88
81
  };
89
82
 
90
83
  const log = async () => {
91
84
  while (true) {
92
- // Non-blocking
85
+ // Block until x is recieved
93
86
  const x = await channel.recieve(c);
94
-
95
- // 'recieve' returns undefined if
96
- // The channel has been closed
97
87
  if (x == null) break;
98
88
 
99
89
  console.log('Recieved', x);
@@ -107,39 +97,51 @@ log();
107
97
  console.log('Starting...');
108
98
  ```
109
99
 
110
- # Pubsub
111
- A simple publish-subscribe API
100
+ ## Latch
101
+ Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
112
102
 
113
103
  ```ts
114
- import * as topic from 'ciorent/topic';
104
+ import * as latch from 'ciorent/latch';
115
105
  import * as cio from 'ciorent';
116
106
 
117
- const messages = topic.init<number>();
107
+ const fetchLatch = latch.init();
118
108
 
119
- // A task that publish messages
120
- const publisher = async () => {
121
- for (let i = 0; i < 5; i++) {
122
- await cio.sleep(50);
123
- topic.pub(messages, i);
124
- }
109
+ const task = async () => {
110
+ // Blocks until the latch is open
111
+ await latch.pause(fetchLatch);
112
+
113
+ const res = await fetch('http://example.com');
114
+ console.log('Fetch status:', res.status);
125
115
  }
126
116
 
127
- // Spawn 5 tasks that recieve messages
128
- cio.concurrent(5, async (id: number) => {
129
- const sub = topic.sub(messages);
117
+ const prepare = () => {
118
+ console.log('Run before fetch:', performance.now().toFixed(2));
119
+ }
130
120
 
131
- while (true) {
132
- const x = await topic.next(sub);
133
- if (x == null) break;
134
- console.log(`Task ${id}: ${x}`);
135
- }
136
- });
121
+ const main = async () => {
122
+ const p = task();
123
+ await cio.sleep(500);
124
+ prepare();
137
125
 
138
- publisher();
126
+ // Allows all previously blocked tasks to run
127
+ latch.open(fetchLatch);
128
+
129
+ // Reclose the latch
130
+ // Tasks that aren't blocked yet will be blocked
131
+ latch.reset(fetchLatch);
132
+
133
+ return p;
134
+ }
135
+
136
+ // Run fetch after 500ms
137
+ await main();
138
+
139
+ // Run fetch after another 500ms
140
+ await main();
139
141
  ```
140
142
 
141
- # Utilities
142
- ## Pausing
143
+ ## Utilities
144
+ ### Pausing
143
145
  Delay the execution of a function for other asynchronous tasks to run.
144
146
  ```ts
145
147
  import * as cio from 'ciorent';
@@ -169,7 +171,7 @@ task1();
169
171
  task2();
170
172
  ```
171
173
 
172
- ## Sleep
174
+ ### Sleep
173
175
  A cross-runtime sleep function.
174
176
  ```ts
175
177
  import { sleep } from 'ciorent';
@@ -178,23 +180,7 @@ await sleep(500);
178
180
  console.log('Hi');
179
181
  ```
180
182
 
181
- ## Basic concurrency
182
- Control how many tasks can be executed concurrently.
183
- ```ts
184
- import concurrent from 'ciorent/concurrent';
185
- import * as cio from 'ciorent';
186
-
187
- // Allow 3 tasks to run at the same time
188
- const run = concurrent(3);
189
-
190
- for (let id = 1; id <= 6; id++)
191
- run(async () => {
192
- await cio.sleep(Math.random() * 20 + 50);
193
- console.log('Task', id, 'done');
194
- });
195
- ```
196
-
197
- ## Spawning tasks
183
+ ### Spawning tasks
198
184
  Creating new tasks with controlled concurrency.
199
185
  ```ts
200
186
  import * as cio from 'ciorent';
@@ -205,16 +191,11 @@ const task = async (id: number) => {
205
191
  }
206
192
 
207
193
  // Spawn and run 5 tasks sequentially
208
- console.log('Running sequentially:');
194
+ console.log('Running 5 tasks sequentially:');
209
195
  cio.sequential(5, task);
210
196
 
211
197
  // Spawn and run 5 tasks concurrently
212
198
  console.log('Running 5 tasks concurrently:');
213
199
  cio.concurrent(5, task);
214
-
215
- // Spawn and run 5 tasks, with the maximum
216
- // tasks running concurrently set to 3
217
- console.log('Running each 3 tasks concurrently:');
218
- cio.concurrent(5, task, 3);
219
200
  ```
220
201
 
package/channel.d.ts CHANGED
@@ -6,26 +6,22 @@ import type { QueueNode } from './fixed-queue';
6
6
  * Describe a channel
7
7
  */
8
8
  export interface Channel<T> {
9
- /**
10
- * Opening state of the channel
11
- */
12
- 0: boolean;
13
9
  /**
14
10
  * The head of the value queue
15
11
  */
16
- 1: QueueNode<T>;
12
+ 0: QueueNode<T>;
17
13
  /**
18
14
  * The tail of the value queue
19
15
  */
20
- 2: QueueNode<T>;
16
+ 1: QueueNode<T>;
21
17
  /**
22
18
  * The head of the Promise resolve queue
23
19
  */
24
- 3: QueueNode<(value?: T) => void>;
20
+ 2: QueueNode<(value?: T) => void>;
25
21
  /**
26
22
  * The tail of the Promise resolve queue
27
23
  */
28
- 4: QueueNode<(value?: T) => void>;
24
+ 3: QueueNode<(value?: T) => void>;
29
25
  }
30
26
  /**
31
27
  * Create a channel
@@ -48,12 +44,7 @@ export declare const recieve: <T>(c: Channel<T>) => Promise<T | undefined>;
48
44
  */
49
45
  export declare const poll: <T>(c: Channel<T>) => T | undefined;
50
46
  /**
51
- * Close a channel
52
- * @param c
53
- */
54
- export declare const close: <T>(c: Channel<T>) => void;
55
- /**
56
- * Check whether a channel is still open
47
+ * Resolves all pending promises of a channel
57
48
  * @param c
58
49
  */
59
- export declare const active: (c: Channel<any>) => boolean;
50
+ export declare const flush: <T>(c: Channel<T>) => void;
package/channel.js CHANGED
@@ -1 +1 @@
1
- import{pause as resolvedPromise}from".";export let init=()=>{let qu=[null,null];let resolveQu=[null,null];return[true,qu,qu,resolveQu,resolveQu]};export let send=(c,t)=>{if(c[0]){if(c[4][1]!==null)(c[4]=c[4][1])[0](t);else c[1]=c[1][1]=[t,null]}};export let recieve=(c)=>c[2][1]!==null?Promise.resolve((c[2]=c[2][1])[0]):c[0]?new Promise((res)=>{c[3]=c[3][1]=[res,null]}):resolvedPromise;export let poll=(c)=>c[2][1]!==null?(c[2]=c[2][1])[0]:undefined;export let close=(c)=>{c[0]=false;while(c[4][1]!==null)(c[4]=c[4][1])[0]()};export let active=(c)=>c[0];
1
+ export let init=()=>{let qu=[null,null];let resolveQu=[null,null];return[qu,qu,resolveQu,resolveQu]};export let send=(c,t)=>{if(c[3][1]!==null)(c[3]=c[3][1])[0](t);else c[0]=c[0][1]=[t,null]};export let recieve=(c)=>c[1][1]!==null?Promise.resolve((c[1]=c[1][1])[0]):new Promise((res)=>{c[2]=c[2][1]=[res,null]});export let poll=(c)=>c[1][1]!==null?(c[1]=c[1][1])[0]:undefined;export let flush=(c)=>{while(c[3][1]!==null)(c[3]=c[3][1])[0]()};
package/concurrent.d.ts CHANGED
@@ -2,12 +2,10 @@
2
2
  * @module Concurrency controls
3
3
  */
4
4
  /**
5
- * Describe a concurrency controller
5
+ * Describe an async task
6
6
  */
7
- export type Controller = <T>(task: () => Promise<T>) => Promise<T>;
7
+ export type Task<T = unknown> = () => Promise<T>;
8
8
  /**
9
- * Create a concurrency controller, allow n tasks to run concurrently
10
- * @param n
9
+ * Describe a concurrency controller
11
10
  */
12
- declare const _default: (n: number) => Controller;
13
- export default _default;
11
+ export type Controller = <T>(task: Task<T>) => Promise<T>;
package/index.d.ts CHANGED
@@ -24,6 +24,5 @@ export declare const sequential: (n: number, task: (id: number) => Promise<any>)
24
24
  * Spawn n tasks that runs concurrently
25
25
  * @param n
26
26
  * @param task - The function to run
27
- * @param concurrency - The amount of task to run concurrently
28
27
  */
29
- export declare const concurrent: (n: number, task: (id: number) => Promise<any>, concurrency?: number) => Promise<any>;
28
+ export declare const concurrent: (n: number, task: (id: number) => Promise<any>) => 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)}));export let sequential=async(n,task)=>{for(let i=0;i<n;i++)await task(i)};export let concurrent=async(n,task,concurrency)=>{if(concurrency==null){let arr=new Array(n);for(let i=0;i<n;i++)arr[i]=task(i);return Promise.all(arr)}let arr=new Array(concurrency);let pre=0;for(let block=n/concurrency>>>0;block>0;block--){for(let j=0;j<concurrency;j++)arr[j]=task(pre+j);await Promise.all(arr);pre+=concurrency}n-=pre;for(let i=0;i<n;i++)arr[i]=task(pre+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)}));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)};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ciorent",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "A lightweight, low-overhead concurrency library",
5
5
  "homepage": "https://ciorent.netlify.app",
6
6
  "repository": {
package/semaphore.d.ts CHANGED
@@ -32,6 +32,6 @@ export declare const pause: (s: Semaphore) => Promise<void>;
32
32
  */
33
33
  export declare const signal: (s: Semaphore) => void;
34
34
  /**
35
- * Create a task that acquire a semaphore and release the access later
35
+ * Create a task that acquire a semaphore and release the access when it's finished
36
36
  */
37
37
  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".";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 task=(s,f)=>async(...a)=>{await pause(s);try{return await f(...a)}finally{signal(s)}};
1
+ import{pause as resolvedPromise}from".";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 task=(s,f)=>async(...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)}};
package/topic.d.ts CHANGED
@@ -41,10 +41,10 @@ export declare const sub: <T extends {}>(t: Topic<T>) => Subscriber<T>;
41
41
  */
42
42
  export declare const pub: <T extends {}>(t: Topic<T>, value: T) => void;
43
43
  /**
44
- * Resolve all waiting promises
44
+ * Resolve all waiting promises and clear all pending values
45
45
  * @param t
46
46
  */
47
- export declare const close: <T extends {}>(t: Topic<T>) => void;
47
+ export declare const flush: <T extends {}>(t: Topic<T>) => void;
48
48
  /**
49
49
  * Get the next value in the message queue.
50
50
  *
@@ -58,4 +58,4 @@ export declare const poll: <T extends {}>(t: Subscriber<T>) => T | undefined;
58
58
  * Returns a promise that resolves when the message queue is not empty
59
59
  * @param t
60
60
  */
61
- export declare const next: <T extends {}>(t: Subscriber<T>) => Promise<T | undefined>;
61
+ export declare const recieve: <T extends {}>(t: Subscriber<T>) => Promise<T | undefined>;
package/topic.js CHANGED
@@ -1 +1 @@
1
- export let init=()=>[[null,null],[],[]];export let sub=(t)=>[t,t[0]];export let pub=(t,value)=>{let head=t[0]=t[0][1]=[value,null];for(let i=0,res=t[1],subs=t[2];i<res.length;i++){res[i](value);subs[i][1]=head}t[1]=[];t[2]=[]};export let close=(t)=>{for(let i=0,res=t[1],subs=t[2],head=t[0];i<res.length;i++){res[i]();subs[i][1]=head}t[1]=[];t[2]=[]};export let poll=(t)=>t[1][1]!==null?(t[1]=t[1][1])[0]:undefined;export let next=(t)=>{if(t[1][1]!==null)return Promise.resolve((t[1]=t[1][1])[0]);let topic=t[0];topic[2].push(t);return new Promise((res)=>{topic[1].push(res)})};
1
+ export let init=()=>[[null,null],[],[]];export let sub=(t)=>[t,t[0]];export let pub=(t,value)=>{let head=t[0]=t[0][1]=[value,null];for(let i=0,res=t[1],subs=t[2];i<res.length;i++){res[i](value);subs[i][1]=head}t[1]=[];t[2]=[]};export let flush=(t)=>{let head=t[0]=[null,null];for(let i=0,res=t[1],subs=t[2];i<res.length;i++){res[i]();subs[i][1]=head}t[1]=[];t[2]=[]};export let poll=(t)=>t[1][1]!==null?(t[1]=t[1][1])[0]:undefined;export let recieve=(t)=>{if(t[1][1]!==null)return Promise.resolve((t[1]=t[1][1])[0]);let topic=t[0];topic[2].push(t);return new Promise((res)=>{topic[1].push(res)})};
package/concurrent.js DELETED
@@ -1 +0,0 @@
1
- export default (n)=>{let pending=new Array(n);let cnt=0;return async(f)=>{if(cnt<n)return pending[cnt++]=f();await Promise.allSettled(pending);cnt=0;return pending[0]=f()}};