ciorent 0.0.8 → 0.0.11
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 +87 -76
- package/channel.d.ts +6 -7
- package/channel.js +1 -1
- package/concurrent.d.ts +1 -2
- package/{queue/dropping.d.ts → dropping-queue.d.ts} +4 -5
- package/dropping-queue.js +1 -0
- package/{queue/index.d.ts → fixed-queue.d.ts} +1 -2
- package/index.d.ts +1 -2
- package/index.js +1 -1
- package/latch.d.ts +1 -2
- package/package.json +6 -4
- package/semaphore.d.ts +2 -3
- package/{queue/sliding.d.ts → sliding-queue.d.ts} +3 -4
- package/sliding-queue.js +1 -0
- package/queue/dropping.js +0 -1
- package/queue/sliding.js +0 -1
- /package/{queue/index.js → fixed-queue.js} +0 -0
package/README.md
CHANGED
@@ -1,53 +1,42 @@
|
|
1
|
-
A low-overhead
|
1
|
+
A lightweight, low-overhead concurrency library
|
2
|
+
|
3
|
+
# Examples
|
4
|
+
## Semaphore
|
5
|
+
Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
|
2
6
|
|
3
|
-
# Usage
|
4
|
-
Pausing to prioritize an asynchronous task:
|
5
7
|
```ts
|
8
|
+
import * as semaphore from 'ciorent/semaphore';
|
6
9
|
import * as cio from 'ciorent';
|
7
10
|
|
8
|
-
//
|
9
|
-
const
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
// Only allow 2 of these tasks to run concurrently
|
12
|
+
const task = semaphore.task(
|
13
|
+
semaphore.init(2),
|
14
|
+
async (task: number) => {
|
15
|
+
for (let i = 1; i <= 5; i++) {
|
16
|
+
console.log('Task', task, 'iteration', i);
|
14
17
|
await cio.pause;
|
18
|
+
}
|
15
19
|
|
16
|
-
|
20
|
+
console.log('Task', task, 'end');
|
17
21
|
}
|
18
|
-
|
19
|
-
};
|
20
|
-
|
21
|
-
// Short async task
|
22
|
-
const task2 = async () => {
|
23
|
-
console.log('Fetch start', performance.now().toFixed(2) + 'ms');
|
24
|
-
const txt = await fetch('http://example.com');
|
25
|
-
console.log('Fetch status', txt.status);
|
26
|
-
};
|
22
|
+
);
|
27
23
|
|
28
|
-
//
|
29
|
-
|
30
|
-
task2();
|
24
|
+
// Try to run 6 tasks with 4 tasks running concurrently
|
25
|
+
cio.concurrent(6, task, 4);
|
31
26
|
```
|
32
27
|
|
33
|
-
|
34
|
-
|
35
|
-
import * as cio from 'ciorent';
|
36
|
-
|
37
|
-
await cio.sleep(1000);
|
38
|
-
console.log('Slept for about 1s');
|
39
|
-
```
|
28
|
+
## Channel
|
29
|
+
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.
|
40
30
|
|
41
|
-
Go-like channels for synchronizations:
|
42
31
|
```ts
|
43
32
|
import * as channel from 'ciorent/channel';
|
44
|
-
import * as cio from 'ciorent';
|
45
33
|
|
46
34
|
const c = channel.init<number>();
|
35
|
+
const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms));
|
47
36
|
|
48
37
|
const run = async () => {
|
49
38
|
for (let i = 0; i < 10; i++) {
|
50
|
-
await
|
39
|
+
await sleep(10);
|
51
40
|
channel.send(c, i);
|
52
41
|
console.log('Sent', i);
|
53
42
|
}
|
@@ -62,8 +51,9 @@ const log = async () => {
|
|
62
51
|
// Non-blocking
|
63
52
|
const x = await channel.recieve(c);
|
64
53
|
|
65
|
-
//
|
66
|
-
|
54
|
+
// 'recieve' returns undefined if
|
55
|
+
// The channel has been closed
|
56
|
+
if (x == null) break;
|
67
57
|
|
68
58
|
console.log('Recieved', x);
|
69
59
|
};
|
@@ -77,7 +67,7 @@ console.log('Starting...');
|
|
77
67
|
```
|
78
68
|
|
79
69
|
## Latch
|
80
|
-
|
70
|
+
Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
|
81
71
|
|
82
72
|
```ts
|
83
73
|
import * as latch from 'ciorent/latch';
|
@@ -119,62 +109,83 @@ await main();
|
|
119
109
|
await main();
|
120
110
|
```
|
121
111
|
|
122
|
-
|
112
|
+
## Utilities
|
113
|
+
### Pausing
|
114
|
+
Delay the execution of a function for other asynchronous tasks to run.
|
123
115
|
```ts
|
124
|
-
import * as latch from 'ciorent/latch';
|
125
116
|
import * as cio from 'ciorent';
|
126
117
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
console.log('Fetch status:', res.status);
|
135
|
-
}
|
118
|
+
// Expensive sync task
|
119
|
+
const task1 = async () => {
|
120
|
+
let x = 0;
|
121
|
+
for (let i = 0; i < (Math.random() + 15) * 1e7; i++) {
|
122
|
+
// Frequent pausing
|
123
|
+
if (i % 2e6 === 0)
|
124
|
+
await cio.pause;
|
136
125
|
|
137
|
-
|
138
|
-
|
126
|
+
x += Math.random() * 32 + i * Math.round(Math.random() * 16);
|
127
|
+
}
|
128
|
+
console.log('Finish task 1:', x);
|
129
|
+
};
|
139
130
|
|
140
|
-
|
141
|
-
|
142
|
-
|
131
|
+
// Short async task
|
132
|
+
const task2 = async () => {
|
133
|
+
console.log('Fetch start', performance.now().toFixed(2) + 'ms');
|
134
|
+
const txt = await fetch('http://example.com');
|
135
|
+
console.log('Fetch status', txt.status);
|
136
|
+
};
|
143
137
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
138
|
+
// Task 2 will not get blocked by task 1
|
139
|
+
task1();
|
140
|
+
task2();
|
141
|
+
```
|
148
142
|
|
149
|
-
|
150
|
-
|
143
|
+
### Sleep
|
144
|
+
A cross-runtime sleep function.
|
145
|
+
```ts
|
146
|
+
import { sleep } from 'ciorent';
|
151
147
|
|
152
|
-
|
153
|
-
|
148
|
+
await sleep(500);
|
149
|
+
console.log('Hi');
|
154
150
|
```
|
155
151
|
|
156
|
-
|
157
|
-
|
152
|
+
### Concurrency
|
153
|
+
Control how many tasks can be executed concurrently.
|
154
|
+
```ts
|
155
|
+
import concurrent from 'ciorent/concurrent';
|
156
|
+
import * as cio from 'ciorent';
|
157
|
+
|
158
|
+
// Allow 3 tasks to run at the same time
|
159
|
+
const run = concurrent(3);
|
158
160
|
|
159
|
-
|
161
|
+
for (let id = 1; id <= 6; id++)
|
162
|
+
run(async () => {
|
163
|
+
await cio.sleep(Math.random() * 20 + 50);
|
164
|
+
console.log('Task', id, 'done');
|
165
|
+
});
|
166
|
+
```
|
160
167
|
|
168
|
+
### Spawning tasks
|
169
|
+
Creating new tasks with controlled concurrency.
|
161
170
|
```ts
|
162
|
-
import * as semaphore from 'ciorent/semaphore';
|
163
171
|
import * as cio from 'ciorent';
|
164
172
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
for (let i = 1; i <= 5; i++) {
|
170
|
-
console.log('Task', task, 'iteration', i);
|
171
|
-
await cio.pause;
|
172
|
-
}
|
173
|
+
const task = async (id: number) => {
|
174
|
+
await cio.sleep(Math.random() * 20 + 50);
|
175
|
+
console.log('Task', id, 'done');
|
176
|
+
}
|
173
177
|
|
174
|
-
|
175
|
-
|
176
|
-
);
|
178
|
+
// Spawn and run 5 tasks sequentially
|
179
|
+
console.log('Running sequentially:');
|
180
|
+
cio.sequential(5, task);
|
177
181
|
|
178
|
-
//
|
179
|
-
|
182
|
+
// Spawn and run 5 tasks concurrently
|
183
|
+
console.log('Running 5 tasks concurrently:');
|
184
|
+
cio.concurrent(5, task);
|
185
|
+
|
186
|
+
// Spawn and run 5 tasks, with the maximum
|
187
|
+
// tasks running concurrently set to 3
|
188
|
+
console.log('Running each 3 tasks concurrently:');
|
189
|
+
cio.concurrent(5, task, 3);
|
180
190
|
```
|
191
|
+
|
package/channel.d.ts
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
/**
|
2
|
-
* @module
|
3
|
-
* Channels
|
2
|
+
* @module Channels
|
4
3
|
*/
|
5
|
-
import type { QueueNode } from './queue';
|
4
|
+
import type { QueueNode } from './fixed-queue';
|
6
5
|
/**
|
7
6
|
* Describe a channel
|
8
7
|
*/
|
@@ -22,11 +21,11 @@ export interface Channel<T> {
|
|
22
21
|
/**
|
23
22
|
* The head of the Promise resolve queue
|
24
23
|
*/
|
25
|
-
3: QueueNode<(value
|
24
|
+
3: QueueNode<(value?: T) => void>;
|
26
25
|
/**
|
27
26
|
* The tail of the Promise resolve queue
|
28
27
|
*/
|
29
|
-
4: QueueNode<(value
|
28
|
+
4: QueueNode<(value?: T) => void>;
|
30
29
|
}
|
31
30
|
/**
|
32
31
|
* Create a channel
|
@@ -42,12 +41,12 @@ export declare const send: <T>(c: Channel<T>, t: T) => void;
|
|
42
41
|
* Recieve a message from a channel, return null if the channel is closed
|
43
42
|
* @param c
|
44
43
|
*/
|
45
|
-
export declare const recieve: <T>(c: Channel<T>) => Promise<T |
|
44
|
+
export declare const recieve: <T>(c: Channel<T>) => Promise<T | undefined>;
|
46
45
|
/**
|
47
46
|
* Recieve a message from a channel, return null if no message is currently in queue
|
48
47
|
* @param c
|
49
48
|
*/
|
50
|
-
export declare const poll: <T>(c: Channel<T>) => T |
|
49
|
+
export declare const poll: <T>(c: Channel<T>) => T | undefined;
|
51
50
|
/**
|
52
51
|
* Close a channel
|
53
52
|
* @param c
|
package/channel.js
CHANGED
@@ -1 +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];
|
package/concurrent.d.ts
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
/**
|
2
|
-
* @module
|
3
|
-
* Dropping queues
|
2
|
+
* @module Dropping queues
|
4
3
|
*/
|
5
|
-
import type { FixedQueue } from '
|
6
|
-
export { default as init } from '
|
7
|
-
export { pop } from './sliding';
|
4
|
+
import type { FixedQueue } from './fixed-queue';
|
5
|
+
export { default as init } from './fixed-queue';
|
6
|
+
export { pop } from './sliding-queue';
|
8
7
|
/**
|
9
8
|
* Push an item to a dropping queue
|
10
9
|
* @param q - The queue to push to
|
@@ -0,0 +1 @@
|
|
1
|
+
export{default as init}from"./fixed-queue";export{pop}from"./sliding-queue";export let push=(q,item)=>{if(q[0][(q[2]+1)%q[1]]!=null)return false;q[0][q[2]=(q[2]+1)%q[1]]=item;return true};
|
package/index.d.ts
CHANGED
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=
|
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)};
|
package/latch.d.ts
CHANGED
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "ciorent",
|
3
|
-
"version": "0.0.
|
4
|
-
"description": "A low-overhead
|
3
|
+
"version": "0.0.11",
|
4
|
+
"description": "A lightweight, low-overhead concurrency library",
|
5
5
|
"homepage": "https://ciorent.netlify.app",
|
6
6
|
"repository": {
|
7
7
|
"type": "github",
|
@@ -10,7 +10,8 @@
|
|
10
10
|
"keywords": [
|
11
11
|
"low-overhead",
|
12
12
|
"lightweight",
|
13
|
-
"concurrency"
|
13
|
+
"concurrency",
|
14
|
+
"cross-runtime"
|
14
15
|
],
|
15
16
|
"license": "MIT",
|
16
17
|
"type": "module",
|
@@ -22,7 +23,7 @@
|
|
22
23
|
"build:publish": "bun build:test && bun task report-size && bun task publish",
|
23
24
|
"lint": "eslint ./src",
|
24
25
|
"lint:fix": "eslint ./src --fix",
|
25
|
-
"docs": "typedoc
|
26
|
+
"docs": "typedoc"
|
26
27
|
},
|
27
28
|
"devDependencies": {
|
28
29
|
"@stylistic/eslint-plugin": "latest",
|
@@ -35,6 +36,7 @@
|
|
35
36
|
"tsx": "latest",
|
36
37
|
"typedoc": "^0.27.9",
|
37
38
|
"typedoc-material-theme": "^1.3.0",
|
39
|
+
"typedoc-plugin-inline-sources": "^1.2.1",
|
38
40
|
"typescript": "latest",
|
39
41
|
"typescript-eslint": "latest"
|
40
42
|
}
|
package/semaphore.d.ts
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
/**
|
2
|
-
* @module
|
3
|
-
* Sliding queues
|
2
|
+
* @module Sliding queues
|
4
3
|
*/
|
5
|
-
import type { FixedQueue } from '
|
6
|
-
export { default as init } from '
|
4
|
+
import type { FixedQueue } from './fixed-queue';
|
5
|
+
export { default as init } from './fixed-queue';
|
7
6
|
/**
|
8
7
|
* Push an item to a sliding queue
|
9
8
|
* @param q - The queue to push to
|
package/sliding-queue.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export{default as init}from"./fixed-queue";export let push=(q,item)=>{q[0][q[2]=(q[2]+1)%q[1]]=item};export let pop=(q)=>{let val=q[0][(q[3]+1)%q[1]];if(val!=null){q[0][q[3]=(q[3]+1)%q[1]]=null;return val}};
|
package/queue/dropping.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export{default as init}from".";export{pop}from"./sliding";export let push=(q,item)=>{if(q[0][(q[2]+1)%q[1]]!=null)return false;q[0][q[2]=(q[2]+1)%q[1]]=item;return true};
|
package/queue/sliding.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export{default as init}from".";export let push=(q,item)=>{q[0][q[2]=(q[2]+1)%q[1]]=item};export let pop=(q)=>{let val=q[0][(q[3]+1)%q[1]];if(val!=null){q[0][q[3]=(q[3]+1)%q[1]]=null;return val}};
|
File without changes
|