ciorent 0.1.4 → 0.2.0
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 +82 -64
- package/fiber.d.ts +3 -3
- package/fiber.js +1 -1
- package/index.d.ts +2 -9
- package/index.js +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
A lightweight, low-overhead concurrency library.
|
2
|
-
|
2
|
+
|
3
|
+
## Features
|
4
|
+
- Micro-optimized utilities.
|
5
|
+
- Performance-oriented API design.
|
6
|
+
- Small bundle size.
|
7
|
+
- Fully type-safe.
|
8
|
+
|
9
|
+
## Examples
|
10
|
+
### Semaphore
|
3
11
|
Semaphore is a concurrency primitive used to control access to a common resource by multiple processes.
|
4
12
|
|
5
13
|
```ts
|
@@ -28,7 +36,7 @@ const task = async (id: number) => {
|
|
28
36
|
co.spawn(5, task);
|
29
37
|
```
|
30
38
|
|
31
|
-
|
39
|
+
### Fibers
|
32
40
|
Virtual threads with more controlled execution.
|
33
41
|
|
34
42
|
```ts
|
@@ -36,58 +44,57 @@ import * as co from 'ciorent';
|
|
36
44
|
import * as fiber from 'ciorent/fiber';
|
37
45
|
|
38
46
|
const f1 = fiber.fn(function* () {
|
39
|
-
console.log('Fiber 1 started');
|
40
|
-
|
41
47
|
// Wait for a promise
|
42
48
|
yield co.sleep(1000);
|
43
49
|
|
44
|
-
|
50
|
+
// Wait for a promise and return its result
|
51
|
+
const res = yield* fiber.unwrap(Promise.resolve(1));
|
52
|
+
console.log('Fiber 1 recieved:', res);
|
53
|
+
|
45
54
|
return Math.random();
|
46
55
|
});
|
47
56
|
|
48
|
-
|
49
|
-
|
57
|
+
{
|
58
|
+
const main = fiber.spawn(function* (proc) {
|
59
|
+
// Start f1, wait for it to finish and get the result
|
60
|
+
const res = yield* fiber.join(fiber.spawn(f1));
|
61
|
+
console.log('Fiber 2 recieved:', res);
|
50
62
|
|
51
|
-
|
52
|
-
|
53
|
-
|
63
|
+
// Start f1 and make its lifetime depends on current fiber
|
64
|
+
const childProc = fiber.spawn(f1);
|
65
|
+
fiber.mount(childProc, proc);
|
66
|
+
});
|
54
67
|
|
55
|
-
|
56
|
-
fiber.mount(fiber.spawn(f1), proc);
|
68
|
+
console.log('Fiber 2 started:', fiber.resumed(main));
|
57
69
|
|
58
|
-
//
|
59
|
-
|
60
|
-
|
61
|
-
```
|
70
|
+
// Pause the current fiber process
|
71
|
+
fiber.pause(main);
|
72
|
+
console.log('Fiber 2 is paused:', fiber.paused(main));
|
62
73
|
|
63
|
-
|
64
|
-
|
74
|
+
// Resume the fiber
|
75
|
+
fiber.resume(main);
|
76
|
+
console.log('Fiber 2 is resumed:', fiber.resumed(main));
|
65
77
|
|
66
|
-
|
67
|
-
|
78
|
+
// Wait for the fiber process to finish
|
79
|
+
await fiber.done(main);
|
68
80
|
|
69
|
-
|
81
|
+
// Check finish status
|
82
|
+
console.log('Fiber 2 completed', fiber.completed(main));
|
83
|
+
}
|
70
84
|
|
71
|
-
|
72
|
-
|
73
|
-
await latch.pause(startFetch);
|
85
|
+
{
|
86
|
+
console.log('------------------------');
|
74
87
|
|
75
|
-
|
76
|
-
|
77
|
-
console.log('Fetch status:', res.status);
|
78
|
-
}
|
88
|
+
const main = fiber.spawn(f1);
|
89
|
+
console.log('Fiber 1 started:', fiber.resumed(main));
|
79
90
|
|
80
|
-
|
81
|
-
|
82
|
-
console.log('
|
83
|
-
latch.open(startFetch);
|
91
|
+
// Stop a fiber
|
92
|
+
fiber.stop(main);
|
93
|
+
console.log('Fiber 1 stopped:', fiber.stopped(main));
|
84
94
|
}
|
85
|
-
|
86
|
-
task();
|
87
|
-
prepare();
|
88
95
|
```
|
89
96
|
|
90
|
-
|
97
|
+
### Pubsub
|
91
98
|
A fast, simple publish-subscribe API.
|
92
99
|
|
93
100
|
```ts
|
@@ -123,7 +130,34 @@ co.spawn(3, async (id: number) => {
|
|
123
130
|
publisher();
|
124
131
|
```
|
125
132
|
|
126
|
-
|
133
|
+
### Latch
|
134
|
+
Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
|
135
|
+
|
136
|
+
```ts
|
137
|
+
import * as latch from 'ciorent/latch';
|
138
|
+
|
139
|
+
const startFetch = latch.init();
|
140
|
+
|
141
|
+
const task = async () => {
|
142
|
+
// Blocks until the latch is open
|
143
|
+
await latch.pause(startFetch);
|
144
|
+
|
145
|
+
console.log('Start fetching...');
|
146
|
+
const res = await fetch('http://example.com');
|
147
|
+
console.log('Fetch status:', res.status);
|
148
|
+
}
|
149
|
+
|
150
|
+
const prepare = () => {
|
151
|
+
// This always run first
|
152
|
+
console.log('Run before fetch:', performance.now().toFixed(2));
|
153
|
+
latch.open(startFetch);
|
154
|
+
}
|
155
|
+
|
156
|
+
task();
|
157
|
+
prepare();
|
158
|
+
```
|
159
|
+
|
160
|
+
### Channel
|
127
161
|
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.
|
128
162
|
|
129
163
|
```ts
|
@@ -161,8 +195,8 @@ run();
|
|
161
195
|
console.log('Starting...');
|
162
196
|
```
|
163
197
|
|
164
|
-
|
165
|
-
|
198
|
+
### Utilities
|
199
|
+
#### Pausing
|
166
200
|
Delay the execution of a function for other asynchronous tasks to run.
|
167
201
|
```ts
|
168
202
|
import * as co from 'ciorent';
|
@@ -194,7 +228,7 @@ task1();
|
|
194
228
|
task2();
|
195
229
|
```
|
196
230
|
|
197
|
-
|
231
|
+
#### Sleep
|
198
232
|
Cross-runtime synchronous and asynchronous sleep functions.
|
199
233
|
```ts
|
200
234
|
import * as co from 'ciorent';
|
@@ -213,7 +247,7 @@ co.sleepSync(500);
|
|
213
247
|
logTime('After another 0.5s');
|
214
248
|
```
|
215
249
|
|
216
|
-
|
250
|
+
#### Spawning tasks
|
217
251
|
Utilities to create and run tasks.
|
218
252
|
```ts
|
219
253
|
import * as co from 'ciorent';
|
@@ -232,7 +266,7 @@ console.log('Running 5 tasks concurrently:');
|
|
232
266
|
await Promise.all(co.spawn(5, task));
|
233
267
|
```
|
234
268
|
|
235
|
-
|
269
|
+
#### Debounce
|
236
270
|
Postpones execution until after an idle period.
|
237
271
|
```ts
|
238
272
|
import * as co from 'ciorent';
|
@@ -246,33 +280,17 @@ await co.sleep(100);
|
|
246
280
|
fn(2); // fn(2) gets executed
|
247
281
|
```
|
248
282
|
|
249
|
-
|
250
|
-
Limits the number of calls within a time window.
|
251
|
-
```ts
|
252
|
-
import * as co from 'ciorent';
|
253
|
-
|
254
|
-
// Allow 2 calls in 500ms, other calls are dropped
|
255
|
-
const fn = co.rateLimit((id: number) => {
|
256
|
-
console.log('Call ' + id + ':', Math.floor(performance.now()) + 'ms');
|
257
|
-
}, 500, 2);
|
258
|
-
|
259
|
-
// Some calls will be dropped
|
260
|
-
for (let i = 0; i < 8; i++) {
|
261
|
-
fn(i);
|
262
|
-
await co.sleep(400);
|
263
|
-
}
|
264
|
-
```
|
265
|
-
|
266
|
-
### Throttle
|
283
|
+
#### Throttle
|
267
284
|
Executes a function at a regular interval.
|
268
285
|
```ts
|
269
286
|
import * as co from 'ciorent';
|
270
287
|
|
271
288
|
// Allow 2 calls in 500ms
|
272
|
-
const
|
273
|
-
console.log(id + ': ' + Math.floor(performance.now()) + 'ms');
|
274
|
-
}, 500, 2);
|
289
|
+
const throttle = co.throttle(500, 2);
|
275
290
|
|
276
|
-
co.spawn(8,
|
291
|
+
co.spawn(8, async (id) => {
|
292
|
+
await throttle();
|
293
|
+
console.log(id + ': ' + Math.floor(performance.now()) + 'ms');
|
294
|
+
});
|
277
295
|
```
|
278
296
|
|
package/fiber.d.ts
CHANGED
@@ -35,9 +35,9 @@ export declare const paused: (t: Process) => boolean;
|
|
35
35
|
*/
|
36
36
|
export declare const resumed: (t: Process) => boolean;
|
37
37
|
/**
|
38
|
-
* Check whether the fiber has
|
38
|
+
* Check whether the fiber has completed
|
39
39
|
*/
|
40
|
-
export declare const
|
40
|
+
export declare const completed: (t: Process) => boolean;
|
41
41
|
/**
|
42
42
|
* Check whether the fiber has been interrupted
|
43
43
|
*/
|
@@ -76,7 +76,7 @@ export declare function join<T extends Process>(t: T): Generator<Awaited<T[0]>,
|
|
76
76
|
* Wait for a fiber to finish and retrieve its result
|
77
77
|
* @param t
|
78
78
|
*/
|
79
|
-
export declare const
|
79
|
+
export declare const done: <T extends Process>(t: T) => T[0];
|
80
80
|
/**
|
81
81
|
* Mount child fiber lifetime to parent lifetime
|
82
82
|
* @param child
|
package/fiber.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export let paused=(t)=>t[1]===0;export let resumed=(t)=>t[1]===1;export let
|
1
|
+
export let paused=(t)=>t[1]===0;export let resumed=(t)=>t[1]===1;export let completed=(t)=>t[1]===2;export let stopped=(t)=>t[1]===3;let invoke=async(g,thread)=>{try{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]===3)return;t=g.next(v)}thread[1]=2;return t.value}finally{if(thread[1]!==2)thread[1]=3;thread[3].forEach(stop)}};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]!==2){if(t[1]===0)t[2]?.();t[1]=3}};export function*join(t){return yield t[0]}export let done=(t)=>t[0];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
@@ -24,7 +24,7 @@ export declare const sleep: (ms: number) => Promise<void>;
|
|
24
24
|
*/
|
25
25
|
export declare const sleepSync: (ms: number) => void;
|
26
26
|
/**
|
27
|
-
* Spawn n
|
27
|
+
* Spawn n sequential task
|
28
28
|
* @param n
|
29
29
|
* @param task - The function to run
|
30
30
|
*/
|
@@ -41,17 +41,10 @@ export declare const spawn: <const T extends any[], const R>(n: number, task: (.
|
|
41
41
|
* @param ms - The time period in milliseconds
|
42
42
|
*/
|
43
43
|
export declare const debounce: <const Args extends any[]>(f: (...args: Args) => any, ms: number) => ((...args: Args) => void);
|
44
|
-
/**
|
45
|
-
* Drop function calls for a specific period
|
46
|
-
* @param f - The target function to rate limit (it must not throw errors)
|
47
|
-
* @param ms - The time period in milliseconds
|
48
|
-
* @param limit - The call limit in the time period
|
49
|
-
*/
|
50
|
-
export declare const rateLimit: <const Args extends any[]>(f: (...args: Args) => any, ms: number, limit: number) => ((...args: Args) => void);
|
51
44
|
/**
|
52
45
|
* Throttle function execution for a time period
|
53
46
|
* @param f - The function to throttle (it must not throw errors)
|
54
47
|
* @param ms - The time in milliseconds
|
55
48
|
* @param limit - The call limit in the time period
|
56
49
|
*/
|
57
|
-
export declare const throttle:
|
50
|
+
export declare const throttle: (ms: number, limit: number) => (() => Promise<void>);
|
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,...args)=>{for(let i=0;i<n;i++)await task(...args,i)};export let spawn=(n,task,...args)=>{let arr=new Array(n);for(let i=0;i<n;i++)arr[i]=task(...args,i);return arr};export let debounce=(f,ms)=>{let id;return(...a)=>{clearTimeout(id);id=setTimeout(f,ms,...a)}};export let
|
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 spawn=(n,task,...args)=>{let arr=new Array(n);for(let i=0;i<n;i++)arr[i]=task(...args,i);return arr};export let debounce=(f,ms)=>{let id;return(...a)=>{clearTimeout(id);id=setTimeout(f,ms,...a)}};export let throttle=(ms,limit)=>{let head=[null];let tail=head;let cur=limit;let scheduled=false;let unlock=()=>{cur=limit;while(cur>0){if(tail===head){scheduled=false;return}cur--;(tail=tail[0])[1]()}setTimeout(unlock,ms)};return()=>{if(cur===0){let r;let p=new Promise((res)=>{r=res});head=head[0]=[null,r];return p}if(!scheduled){scheduled=true;setTimeout(unlock,ms)}cur--;return pause}};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "ciorent",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.2.0",
|
4
4
|
"description": "A lightweight, low-overhead concurrency library",
|
5
5
|
"homepage": "https://ciorent.netlify.app",
|
6
6
|
"repository": {
|
@@ -19,13 +19,13 @@
|
|
19
19
|
"types": "./index.d.ts",
|
20
20
|
"exports": {
|
21
21
|
"./fixed-queue": "./fixed-queue.js",
|
22
|
-
"./
|
22
|
+
"./fiber": "./fiber.js",
|
23
23
|
"./sliding-queue": "./sliding-queue.js",
|
24
|
-
".": "./index.js",
|
25
|
-
"./topic": "./topic.js",
|
26
24
|
"./semaphore": "./semaphore.js",
|
25
|
+
"./dropping-queue": "./dropping-queue.js",
|
27
26
|
"./channel": "./channel.js",
|
28
|
-
"
|
27
|
+
".": "./index.js",
|
28
|
+
"./topic": "./topic.js",
|
29
29
|
"./latch": "./latch.js"
|
30
30
|
}
|
31
31
|
}
|