ciorent 0.0.14 → 0.0.16

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,29 @@
1
1
  A lightweight, low-overhead concurrency library.
2
- # Latch
2
+ ## Semaphore
3
+ Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
4
+
5
+ ```ts
6
+ import * as semaphore from 'ciorent/semaphore';
7
+ import * as cio from 'ciorent';
8
+
9
+ // Only allow 2 of these tasks to run concurrently
10
+ const task = semaphore.task(
11
+ semaphore.init(2),
12
+ async (task: number) => {
13
+ for (let i = 1; i <= 5; i++) {
14
+ console.log('Task', task, 'iteration', i);
15
+ await cio.pause;
16
+ }
17
+
18
+ console.log('Task', task, 'end');
19
+ }
20
+ );
21
+
22
+ // Try to run 6 tasks concurrently
23
+ cio.concurrent(6, task);
24
+ ```
25
+
26
+ ## Latch
3
27
  Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
4
28
 
5
29
  ```ts
@@ -42,7 +66,7 @@ await main();
42
66
  await main();
43
67
  ```
44
68
 
45
- # Pubsub
69
+ ## Pubsub
46
70
  A fast, simple publish-subscribe API.
47
71
 
48
72
  ```ts
@@ -54,7 +78,7 @@ const messages = topic.init<number>();
54
78
  // A task that publish messages
55
79
  const publisher = async () => {
56
80
  for (let i = 0; i < 5; i++) {
57
- await cio.sleep(50);
81
+ await cio.sleep(100);
58
82
  topic.pub(messages, i);
59
83
  }
60
84
 
@@ -68,8 +92,8 @@ cio.concurrent(5, async (id: number) => {
68
92
  const sub = topic.sub(messages);
69
93
 
70
94
  while (true) {
71
- // Block until
72
- const x = await topic.next(sub);
95
+ // Block until the value is sent
96
+ const x = await topic.recieve(sub);
73
97
  if (x == null) break;
74
98
  console.log(`Task ${id}: ${x}`);
75
99
  }
@@ -78,31 +102,7 @@ cio.concurrent(5, async (id: number) => {
78
102
  publisher();
79
103
  ```
80
104
 
81
- # Semaphore
82
- Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
83
-
84
- ```ts
85
- import * as semaphore from 'ciorent/semaphore';
86
- import * as cio from 'ciorent';
87
-
88
- // Only allow 2 of these tasks to run concurrently
89
- const task = semaphore.task(
90
- semaphore.init(2),
91
- async (task: number) => {
92
- for (let i = 1; i <= 5; i++) {
93
- console.log('Task', task, 'iteration', i);
94
- await cio.pause;
95
- }
96
-
97
- console.log('Task', task, 'end');
98
- }
99
- );
100
-
101
- // Try to run 6 tasks with 4 tasks running concurrently
102
- cio.concurrent(6, task, 4);
103
- ```
104
-
105
- # Channel
105
+ ## Channel
106
106
  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.
107
107
 
108
108
  ```ts
@@ -118,18 +118,15 @@ const run = async () => {
118
118
  console.log('Sent', i);
119
119
  }
120
120
 
121
- // Send the closed signal to the reciever
122
- // Or else channel.recieve will block forever
123
- channel.close(c);
121
+ // Resolve all waiting promises with `undefined`
122
+ // This is a way to tell the reciever to not listen to more data
123
+ channel.flush(c);
124
124
  };
125
125
 
126
126
  const log = async () => {
127
127
  while (true) {
128
- // Non-blocking
128
+ // Wait until a value is sent
129
129
  const x = await channel.recieve(c);
130
-
131
- // 'recieve' returns undefined if
132
- // The channel has been closed
133
130
  if (x == null) break;
134
131
 
135
132
  console.log('Recieved', x);
@@ -143,8 +140,8 @@ log();
143
140
  console.log('Starting...');
144
141
  ```
145
142
 
146
- # Utilities
147
- ## Pausing
143
+ ## Utilities
144
+ ### Pausing
148
145
  Delay the execution of a function for other asynchronous tasks to run.
149
146
  ```ts
150
147
  import * as cio from 'ciorent';
@@ -174,7 +171,7 @@ task1();
174
171
  task2();
175
172
  ```
176
173
 
177
- ## Sleep
174
+ ### Sleep
178
175
  A cross-runtime sleep function.
179
176
  ```ts
180
177
  import { sleep } from 'ciorent';
@@ -183,24 +180,8 @@ await sleep(500);
183
180
  console.log('Hi');
184
181
  ```
185
182
 
186
- ## Basic concurrency
187
- Control how many tasks can be executed concurrently.
188
- ```ts
189
- import concurrent from 'ciorent/concurrent';
190
- import * as cio from 'ciorent';
191
-
192
- // Allow 3 tasks to run at the same time
193
- const run = concurrent(3);
194
-
195
- for (let id = 1; id <= 6; id++)
196
- run(async () => {
197
- await cio.sleep(Math.random() * 20 + 50);
198
- console.log('Task', id, 'done');
199
- });
200
- ```
201
-
202
- ## Spawning tasks
203
- Creating new tasks with controlled concurrency.
183
+ ### Spawning tasks
184
+ Utilities to create and run tasks.
204
185
  ```ts
205
186
  import * as cio from 'ciorent';
206
187
 
@@ -210,16 +191,11 @@ const task = async (id: number) => {
210
191
  }
211
192
 
212
193
  // Spawn and run 5 tasks sequentially
213
- console.log('Running sequentially:');
194
+ console.log('Running 5 tasks sequentially:');
214
195
  cio.sequential(5, task);
215
196
 
216
197
  // Spawn and run 5 tasks concurrently
217
198
  console.log('Running 5 tasks concurrently:');
218
199
  cio.concurrent(5, task);
219
-
220
- // Spawn and run 5 tasks, with the maximum
221
- // tasks running concurrently set to 3
222
- console.log('Running each 3 tasks concurrently:');
223
- cio.concurrent(5, task, 3);
224
200
  ```
225
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.14",
3
+ "version": "0.0.16",
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,10 @@ 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
+ * Wrap a task to bind to a custom semaphore later
36
+ */
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
36
40
  */
37
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".";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 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)};
package/topic.d.ts CHANGED
@@ -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 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 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()}};