ciorent 0.0.16 → 0.0.18
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 +90 -52
- package/channel.d.ts +1 -1
- package/dropping-queue.d.ts +3 -3
- package/dropping-queue.js +1 -1
- package/fiber/index.d.ts +74 -0
- package/fiber/index.js +1 -0
- package/fixed-queue.d.ts +1 -4
- package/index.d.ts +7 -0
- package/index.js +1 -1
- package/latch.d.ts +1 -4
- package/latch.js +1 -1
- package/package.json +13 -24
- package/semaphore.d.ts +2 -2
- package/semaphore.js +1 -1
- package/sliding-queue.d.ts +2 -2
- package/sliding-queue.js +1 -1
- package/topic.d.ts +1 -1
package/README.md
CHANGED
@@ -23,47 +23,77 @@ const task = semaphore.task(
|
|
23
23
|
cio.concurrent(6, task);
|
24
24
|
```
|
25
25
|
|
26
|
-
##
|
27
|
-
|
26
|
+
## Fibers
|
27
|
+
Virtual threads with more controlled execution.
|
28
28
|
|
29
29
|
```ts
|
30
|
-
import * as latch from 'ciorent/latch';
|
31
30
|
import * as cio from 'ciorent';
|
31
|
+
import * as fiber from 'ciorent/fiber';
|
32
32
|
|
33
|
-
|
33
|
+
function* thread1() {
|
34
|
+
console.log('Fiber 1 started');
|
35
|
+
yield;
|
36
|
+
console.log('Fiber 1 done');
|
37
|
+
}
|
34
38
|
|
35
|
-
|
36
|
-
|
37
|
-
await latch.pause(fetchLatch);
|
39
|
+
function* thread2() {
|
40
|
+
console.log('Fiber 2 started');
|
38
41
|
|
39
|
-
|
40
|
-
console.log('
|
41
|
-
}
|
42
|
+
yield;
|
43
|
+
console.log('Fiber 2 resumed');
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
+
// Wait for a promise
|
46
|
+
yield* fiber.wait(cio.sleep(1000));
|
47
|
+
console.log('Fiber 2 waited for 1s');
|
48
|
+
|
49
|
+
// Start task 1 and wait for it to be done
|
50
|
+
yield* fiber.join(
|
51
|
+
fiber.start(thread1())
|
52
|
+
);
|
53
|
+
|
54
|
+
console.log('Fiber 2 done');
|
45
55
|
}
|
46
56
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
prepare();
|
57
|
+
// Start running the thread
|
58
|
+
fiber.start(thread2());
|
59
|
+
```
|
51
60
|
|
52
|
-
|
53
|
-
|
61
|
+
## Channel
|
62
|
+
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.
|
54
63
|
|
55
|
-
|
56
|
-
|
57
|
-
|
64
|
+
```ts
|
65
|
+
import * as channel from 'ciorent/channel';
|
66
|
+
import * as cio from 'ciorent';
|
58
67
|
|
59
|
-
|
68
|
+
const c = channel.init<number>();
|
69
|
+
|
70
|
+
const run = async () => {
|
71
|
+
for (let i = 0; i < 10; i++) {
|
72
|
+
await cio.sleep(10);
|
73
|
+
channel.send(c, i);
|
74
|
+
console.log('Sent', i);
|
75
|
+
}
|
76
|
+
|
77
|
+
// Resolve all waiting promises with `undefined`
|
78
|
+
// This is a way to tell the reciever to not listen to more data
|
79
|
+
channel.flush(c);
|
80
|
+
};
|
81
|
+
|
82
|
+
const log = async () => {
|
83
|
+
while (true) {
|
84
|
+
// Wait until a value is sent
|
85
|
+
const x = await channel.recieve(c);
|
86
|
+
if (x == null) break;
|
87
|
+
|
88
|
+
console.log('Recieved', x);
|
89
|
+
};
|
60
90
|
}
|
61
91
|
|
62
|
-
|
63
|
-
|
92
|
+
run();
|
93
|
+
log();
|
64
94
|
|
65
|
-
//
|
66
|
-
|
95
|
+
// This runs first
|
96
|
+
console.log('Starting...');
|
67
97
|
```
|
68
98
|
|
69
99
|
## Pubsub
|
@@ -102,42 +132,47 @@ cio.concurrent(5, async (id: number) => {
|
|
102
132
|
publisher();
|
103
133
|
```
|
104
134
|
|
105
|
-
##
|
106
|
-
|
135
|
+
## Latch
|
136
|
+
Latch is a synchronization primitive that allows one process to wait until another completes an operation before continuing execution.
|
107
137
|
|
108
138
|
```ts
|
109
|
-
import * as
|
139
|
+
import * as latch from 'ciorent/latch';
|
110
140
|
import * as cio from 'ciorent';
|
111
141
|
|
112
|
-
const
|
142
|
+
const fetchLatch = latch.init();
|
113
143
|
|
114
|
-
const
|
115
|
-
|
116
|
-
|
117
|
-
channel.send(c, i);
|
118
|
-
console.log('Sent', i);
|
119
|
-
}
|
144
|
+
const task = async () => {
|
145
|
+
// Blocks until the latch is open
|
146
|
+
await latch.pause(fetchLatch);
|
120
147
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
};
|
148
|
+
const res = await fetch('http://example.com');
|
149
|
+
console.log('Fetch status:', res.status);
|
150
|
+
}
|
125
151
|
|
126
|
-
const
|
127
|
-
|
128
|
-
|
129
|
-
const x = await channel.recieve(c);
|
130
|
-
if (x == null) break;
|
152
|
+
const prepare = () => {
|
153
|
+
console.log('Run before fetch:', performance.now().toFixed(2));
|
154
|
+
}
|
131
155
|
|
132
|
-
|
133
|
-
|
156
|
+
const main = async () => {
|
157
|
+
const p = task();
|
158
|
+
await cio.sleep(500);
|
159
|
+
prepare();
|
160
|
+
|
161
|
+
// Allows all previously blocked tasks to run
|
162
|
+
latch.open(fetchLatch);
|
163
|
+
|
164
|
+
// Reclose the latch
|
165
|
+
// Tasks that aren't blocked yet will be blocked
|
166
|
+
latch.reset(fetchLatch);
|
167
|
+
|
168
|
+
return p;
|
134
169
|
}
|
135
170
|
|
136
|
-
|
137
|
-
|
171
|
+
// Run fetch after 500ms
|
172
|
+
await main();
|
138
173
|
|
139
|
-
//
|
140
|
-
|
174
|
+
// Run fetch after another 500ms
|
175
|
+
await main();
|
141
176
|
```
|
142
177
|
|
143
178
|
## Utilities
|
@@ -174,10 +209,13 @@ task2();
|
|
174
209
|
### Sleep
|
175
210
|
A cross-runtime sleep function.
|
176
211
|
```ts
|
177
|
-
import { sleep } from 'ciorent';
|
212
|
+
import { sleep, sleepSync } from 'ciorent';
|
178
213
|
|
179
214
|
await sleep(500);
|
180
215
|
console.log('Hi');
|
216
|
+
|
217
|
+
sleepSync(500);
|
218
|
+
console.log('Hi');
|
181
219
|
```
|
182
220
|
|
183
221
|
### Spawning tasks
|
package/channel.d.ts
CHANGED
package/dropping-queue.d.ts
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
/**
|
2
2
|
* @module Dropping queues
|
3
3
|
*/
|
4
|
-
import type { FixedQueue } from './fixed-queue';
|
5
|
-
export { init } from './fixed-queue';
|
6
|
-
export { pop } from './sliding-queue';
|
4
|
+
import type { FixedQueue } from './fixed-queue.js';
|
5
|
+
export { init } from './fixed-queue.js';
|
6
|
+
export { pop } from './sliding-queue.js';
|
7
7
|
/**
|
8
8
|
* Push an item to a dropping queue
|
9
9
|
* @param q - The queue to push to
|
package/dropping-queue.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export{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};
|
1
|
+
export{init}from"./fixed-queue.js";export{pop}from"./sliding-queue.js";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/fiber/index.d.ts
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
/**
|
2
|
+
* @module Fiber
|
3
|
+
*/
|
4
|
+
/**
|
5
|
+
* When the fiber is paused
|
6
|
+
*/
|
7
|
+
export declare const paused: (t: Thread) => boolean;
|
8
|
+
/**
|
9
|
+
* When the fiber is running
|
10
|
+
*/
|
11
|
+
export declare const running: (t: Thread) => boolean;
|
12
|
+
/**
|
13
|
+
* When the fiber is done
|
14
|
+
*/
|
15
|
+
export declare const done: (t: Thread) => boolean;
|
16
|
+
/**
|
17
|
+
* Describe a fiber
|
18
|
+
*/
|
19
|
+
export interface Thread<T = unknown, TReturn = unknown> {
|
20
|
+
/**
|
21
|
+
* The original generator
|
22
|
+
*/
|
23
|
+
0: Generator<T, TReturn>;
|
24
|
+
/**
|
25
|
+
* The waiting promise
|
26
|
+
*/
|
27
|
+
1: Promise<T | TReturn>;
|
28
|
+
/**
|
29
|
+
* Fiber status
|
30
|
+
*/
|
31
|
+
2: 0 | 1 | 2;
|
32
|
+
/**
|
33
|
+
* Callback to continue running the fiber
|
34
|
+
*/
|
35
|
+
3: null | (() => void);
|
36
|
+
}
|
37
|
+
/**
|
38
|
+
* Describe a fiber runtime
|
39
|
+
*/
|
40
|
+
export type Runtime = <const T, const TReturn>(gen: Generator<T, TReturn>) => Thread<T, TReturn>;
|
41
|
+
/**
|
42
|
+
* A basic fiber runtime
|
43
|
+
* @param g
|
44
|
+
*/
|
45
|
+
export declare const start: Runtime;
|
46
|
+
/**
|
47
|
+
* Pause the execution of a fiber
|
48
|
+
* @param t
|
49
|
+
*/
|
50
|
+
export declare const pause: (t: Thread) => void;
|
51
|
+
/**
|
52
|
+
* Resume the execution of a fiber
|
53
|
+
* @param t
|
54
|
+
*/
|
55
|
+
export declare const resume: (t: Thread) => void;
|
56
|
+
/**
|
57
|
+
* Stop the execution of a fiber and retrieve the result
|
58
|
+
* @param t
|
59
|
+
*/
|
60
|
+
export declare const stop: <T extends Thread>(t: T) => T[1];
|
61
|
+
/**
|
62
|
+
* Wait for a fiber and retrieve its result
|
63
|
+
* @param t
|
64
|
+
*/
|
65
|
+
export declare function join<T extends Thread>(t: T): Generator<Awaited<T[1]>, Awaited<T[1]>>;
|
66
|
+
/**
|
67
|
+
* Wait for a fiber to finish and retrieve its result
|
68
|
+
* @param t
|
69
|
+
*/
|
70
|
+
export declare const finish: <T extends Thread>(t: T) => T[1];
|
71
|
+
/**
|
72
|
+
* Wait for a promise to resolve then retrieve its result
|
73
|
+
*/
|
74
|
+
export declare function wait<T extends Promise<any>>(t: T): Generator<Awaited<T>, Awaited<T>>;
|
package/fiber/index.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export let paused=(t)=>t[2]===0;export let running=(t)=>t[2]===1;export let done=(t)=>t[2]===2;let invoke=async(g,thread)=>{let t=g.next();while(!t.done){let v=await t.value;if(thread[2]===0){let r;let p=new Promise((res)=>{r=res});thread[3]=r;await p}if(thread[2]===2)return v;t=g.next(v)}thread[2]=2;return t.value};export let start=(g)=>{let thread=[g,null,1,null];thread[1]=invoke(g,thread);return thread};export let pause=(t)=>{if(t[2]===1)t[2]=0};export let resume=(t)=>{if(t[2]===0){t[2]=1;t[3]?.()}};export let stop=(t)=>{if(t[2]===0){t[2]=2;t[3]()}else t[2]=2;return t[1]};export function*join(t){return yield t[1]}export let finish=(t)=>t[1];export function*wait(t){return yield t}
|
package/fixed-queue.d.ts
CHANGED
@@ -26,10 +26,7 @@ export interface FixedQueue<T extends {}> {
|
|
26
26
|
/**
|
27
27
|
* Describe a queue node (singly linked list node)
|
28
28
|
*/
|
29
|
-
export type QueueNode<T> = [
|
30
|
-
value: T,
|
31
|
-
next: QueueNode<T> | null
|
32
|
-
];
|
29
|
+
export type QueueNode<T> = [value: T, next: QueueNode<T> | null];
|
33
30
|
/**
|
34
31
|
* Create a fixed queue.
|
35
32
|
* @param n - The queue size
|
package/index.d.ts
CHANGED
@@ -14,6 +14,13 @@ export declare const pause: Promise<void>;
|
|
14
14
|
* @param ms - Sleep duration in milliseconds
|
15
15
|
*/
|
16
16
|
export declare const sleep: (ms: number) => Promise<void>;
|
17
|
+
/**
|
18
|
+
* Sleep for a duration synchronously.
|
19
|
+
*
|
20
|
+
* On the browser it only works in workers.
|
21
|
+
* @param ms - Sleep duration in milliseconds
|
22
|
+
*/
|
23
|
+
export declare const sleepSync: (ms: number) => void;
|
17
24
|
/**
|
18
25
|
* Spawn n tasks that runs sequentially
|
19
26
|
* @param n
|
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=(n,task)=>{let arr=new Array(n);for(let i=0;i<n;i++)arr[i]=task(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)}));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)=>{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/latch.d.ts
CHANGED
package/latch.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
import{pause as endPromise}from".";export let init=()=>{let r;return[new Promise((res)=>{r=res}),r]};export let pause=(latch)=>latch[0];export let open=(latch)=>{latch[1]();latch[0]=endPromise};export let reset=(latch)=>{if(latch[0]===endPromise){let r;latch[0]=new Promise((res)=>{r=res});latch[1]=r}};
|
1
|
+
import{pause as endPromise}from"./index.js";export let init=()=>{let r;return[new Promise((res)=>{r=res}),r]};export let pause=(latch)=>latch[0];export let open=(latch)=>{latch[1]();latch[0]=endPromise};export let reset=(latch)=>{if(latch[0]===endPromise){let r;latch[0]=new Promise((res)=>{r=res});latch[1]=r}};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "ciorent",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.18",
|
4
4
|
"description": "A lightweight, low-overhead concurrency library",
|
5
5
|
"homepage": "https://ciorent.netlify.app",
|
6
6
|
"repository": {
|
@@ -17,27 +17,16 @@
|
|
17
17
|
"type": "module",
|
18
18
|
"main": "./index.js",
|
19
19
|
"types": "./index.d.ts",
|
20
|
-
"
|
21
|
-
"
|
22
|
-
"
|
23
|
-
"
|
24
|
-
"
|
25
|
-
"
|
26
|
-
"
|
27
|
-
|
28
|
-
|
29
|
-
"
|
30
|
-
"
|
31
|
-
"@types/uglify-js": "latest",
|
32
|
-
"eslint": "latest",
|
33
|
-
"eslint-plugin-jsdoc": "latest",
|
34
|
-
"mitata": "latest",
|
35
|
-
"terser": "^5.39.0",
|
36
|
-
"tsx": "latest",
|
37
|
-
"typedoc": "^0.27.9",
|
38
|
-
"typedoc-material-theme": "^1.3.0",
|
39
|
-
"typedoc-plugin-inline-sources": "^1.2.1",
|
40
|
-
"typescript": "latest",
|
41
|
-
"typescript-eslint": "latest"
|
20
|
+
"exports": {
|
21
|
+
"./fixed-queue": "./fixed-queue.js",
|
22
|
+
"./sliding-queue": "./sliding-queue.js",
|
23
|
+
".": "./index.js",
|
24
|
+
"./dropping-queue": "./dropping-queue.js",
|
25
|
+
"./semaphore": "./semaphore.js",
|
26
|
+
"./channel": "./channel.js",
|
27
|
+
"./fiber": "./fiber/index.js",
|
28
|
+
"./latch": "./latch.js",
|
29
|
+
"./concurrent": "./concurrent.d.ts",
|
30
|
+
"./topic": "./topic.js"
|
42
31
|
}
|
43
|
-
}
|
32
|
+
}
|
package/semaphore.d.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/**
|
2
2
|
* @module Semaphores
|
3
3
|
*/
|
4
|
-
import type { QueueNode } from './fixed-queue';
|
4
|
+
import type { QueueNode } from './fixed-queue.js';
|
5
5
|
/**
|
6
6
|
* Describe a semaphore
|
7
7
|
*/
|
@@ -34,7 +34,7 @@ export declare const signal: (s: Semaphore) => void;
|
|
34
34
|
/**
|
35
35
|
* Wrap a task to bind to a custom semaphore later
|
36
36
|
*/
|
37
|
-
export declare const wrap: <Args extends any[], Return extends Promise<any>>(f: (...args: Args) => Return) => (s: Semaphore, ...a: Args) => Return;
|
37
|
+
export declare const wrap: <Args extends any[], Return extends Promise<any>>(f: (...args: Args) => Return) => ((s: Semaphore, ...a: Args) => Return);
|
38
38
|
/**
|
39
39
|
* Create a task that acquire a semaphore and release the access when it's finished
|
40
40
|
*/
|
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 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)};
|
1
|
+
import{pause as resolvedPromise}from"./index.js";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/sliding-queue.d.ts
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
/**
|
2
2
|
* @module Sliding queues
|
3
3
|
*/
|
4
|
-
import type { FixedQueue } from './fixed-queue';
|
5
|
-
export { init } from './fixed-queue';
|
4
|
+
import type { FixedQueue } from './fixed-queue.js';
|
5
|
+
export { init } from './fixed-queue.js';
|
6
6
|
/**
|
7
7
|
* Push an item to a sliding queue
|
8
8
|
* @param q - The queue to push to
|
package/sliding-queue.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export{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}};
|
1
|
+
export{init}from"./fixed-queue.js";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}};
|