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 +40 -64
- package/channel.d.ts +6 -15
- package/channel.js +1 -1
- package/concurrent.d.ts +4 -6
- package/index.d.ts +1 -2
- package/index.js +1 -1
- package/package.json +1 -1
- package/semaphore.d.ts +5 -1
- package/semaphore.js +1 -1
- package/topic.d.ts +1 -1
- package/topic.js +1 -1
- package/concurrent.js +0 -1
package/README.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
A lightweight, low-overhead concurrency library.
|
2
|
-
|
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
|
-
|
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(
|
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.
|
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
|
-
|
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
|
-
//
|
122
|
-
//
|
123
|
-
channel.
|
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
|
-
//
|
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
|
-
|
147
|
-
|
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
|
-
|
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
|
-
|
187
|
-
|
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
|
-
|
12
|
+
0: QueueNode<T>;
|
17
13
|
/**
|
18
14
|
* The tail of the value queue
|
19
15
|
*/
|
20
|
-
|
16
|
+
1: QueueNode<T>;
|
21
17
|
/**
|
22
18
|
* The head of the Promise resolve queue
|
23
19
|
*/
|
24
|
-
|
20
|
+
2: QueueNode<(value?: T) => void>;
|
25
21
|
/**
|
26
22
|
* The tail of the Promise resolve queue
|
27
23
|
*/
|
28
|
-
|
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
|
-
*
|
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
|
50
|
+
export declare const flush: <T>(c: Channel<T>) => void;
|
package/channel.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
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
|
5
|
+
* Describe an async task
|
6
6
|
*/
|
7
|
-
export type
|
7
|
+
export type Task<T = unknown> = () => Promise<T>;
|
8
8
|
/**
|
9
|
-
*
|
10
|
-
* @param n
|
9
|
+
* Describe a concurrency controller
|
11
10
|
*/
|
12
|
-
|
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
|
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=
|
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
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
|
-
*
|
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
|
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
|
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
|
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()}};
|