concurrent-c-node 0.2.0__tar.gz → 0.3.0__tar.gz
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.
- {concurrent_c_node-0.2.0 → concurrent_c_node-0.3.0}/PKG-INFO +24 -6
- {concurrent_c_node-0.2.0 → concurrent_c_node-0.3.0}/README.md +23 -5
- {concurrent_c_node-0.2.0 → concurrent_c_node-0.3.0}/cc_node/__init__.py +99 -33
- concurrent_c_node-0.3.0/cc_node/examples/__init__.py +0 -0
- concurrent_c_node-0.3.0/cc_node/examples/bench_wire.py +47 -0
- concurrent_c_node-0.3.0/cc_node/examples/use_node.py +32 -0
- {concurrent_c_node-0.2.0 → concurrent_c_node-0.3.0}/concurrent_c_node.egg-info/PKG-INFO +24 -6
- {concurrent_c_node-0.2.0 → concurrent_c_node-0.3.0}/concurrent_c_node.egg-info/SOURCES.txt +3 -0
- {concurrent_c_node-0.2.0 → concurrent_c_node-0.3.0}/pyproject.toml +3 -2
- {concurrent_c_node-0.2.0 → concurrent_c_node-0.3.0}/cc_node/broker.cjs +0 -0
- {concurrent_c_node-0.2.0 → concurrent_c_node-0.3.0}/concurrent_c_node.egg-info/dependency_links.txt +0 -0
- {concurrent_c_node-0.2.0 → concurrent_c_node-0.3.0}/concurrent_c_node.egg-info/top_level.txt +0 -0
- {concurrent_c_node-0.2.0 → concurrent_c_node-0.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: concurrent-c-node
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: JavaScript and npm packages from Python over the Concurrent-C bridge: one spawned Node child per domain, host-controlled lifetime.
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/sreekotay/concurrent-c
|
|
@@ -40,9 +40,11 @@ array in **9ms** where the same values as a JSON list take 583ms.
|
|
|
40
40
|
|
|
41
41
|
```
|
|
42
42
|
pip install concurrent-c-node # needs node on PATH (or point at one)
|
|
43
|
+
python -m cc_node.examples.use_node
|
|
44
|
+
python -m cc_node.examples.bench_wire
|
|
43
45
|
```
|
|
44
46
|
|
|
45
|
-
Import stays `import cc_node`. The mirror of
|
|
47
|
+
Import stays `import cc_node`. Examples ship in the wheel. The mirror of
|
|
46
48
|
[`concurrent-c-python`](https://github.com/sreekotay/concurrent-c/tree/main/npm/cc-python)
|
|
47
49
|
— same domain model, same materialization rules, pointed the other way:
|
|
48
50
|
|
|
@@ -117,11 +119,22 @@ And *which packages* it sees is the working directory's
|
|
|
117
119
|
Run Python in your project, get your project's packages: `npm install`
|
|
118
120
|
next to your program is the whole setup.
|
|
119
121
|
|
|
122
|
+
## Publishing
|
|
123
|
+
|
|
124
|
+
From the Concurrent-C repo root (packs this wheel and the npm sibling):
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
./scripts/publish_bridges.sh # → out/pypi/concurrent_c_node-* (+ npm tgz)
|
|
128
|
+
./scripts/publish_bridges.sh --publish # bump patch, pack, twine + npm publish
|
|
129
|
+
```
|
|
130
|
+
|
|
120
131
|
## Measured
|
|
121
132
|
|
|
122
|
-
From
|
|
123
|
-
|
|
124
|
-
|
|
133
|
+
From `python -m cc_node.examples.bench_wire` (sources under
|
|
134
|
+
[`cc_node/examples/`](https://github.com/sreekotay/concurrent-c/blob/main/pypi/cc-node/cc_node/examples/))
|
|
135
|
+
on a 4-vCPU x86-64 box, node 22 / python 3.11
|
|
136
|
+
([`perf/baselines/cc_node_bridge_py_20260809.txt`](https://github.com/sreekotay/concurrent-c/blob/main/perf/baselines/cc_node_bridge_py_20260809.txt);
|
|
137
|
+
catalog: [`perf/baselines/README.md`](https://github.com/sreekotay/concurrent-c/blob/main/perf/baselines/README.md)):
|
|
125
138
|
|
|
126
139
|
| what | result |
|
|
127
140
|
|---|---|
|
|
@@ -138,7 +151,12 @@ future work.
|
|
|
138
151
|
|
|
139
152
|
A worked tour (builtin Node modules, chains, callbacks, thenables,
|
|
140
153
|
buffers — no npm install needed):
|
|
141
|
-
|
|
154
|
+
`python -m cc_node.examples.use_node`.
|
|
155
|
+
|
|
156
|
+
Adversarial multi-child storm (fanout, callback blizzard, shm hail,
|
|
157
|
+
teardown derby): [`stress/bridge/`](https://github.com/sreekotay/concurrent-c/tree/main/stress/bridge)
|
|
158
|
+
— `./stress/bridge/run.sh` (`CHAOS_SCALE=full` for bigger N; latency demos
|
|
159
|
+
stay in `cc_node/examples/`).
|
|
142
160
|
|
|
143
161
|
And when the hot path is YOUR code rather than an npm package, skip the
|
|
144
162
|
wire entirely: a page of Concurrent-C (or C) exports as a native module
|
|
@@ -29,9 +29,11 @@ array in **9ms** where the same values as a JSON list take 583ms.
|
|
|
29
29
|
|
|
30
30
|
```
|
|
31
31
|
pip install concurrent-c-node # needs node on PATH (or point at one)
|
|
32
|
+
python -m cc_node.examples.use_node
|
|
33
|
+
python -m cc_node.examples.bench_wire
|
|
32
34
|
```
|
|
33
35
|
|
|
34
|
-
Import stays `import cc_node`. The mirror of
|
|
36
|
+
Import stays `import cc_node`. Examples ship in the wheel. The mirror of
|
|
35
37
|
[`concurrent-c-python`](https://github.com/sreekotay/concurrent-c/tree/main/npm/cc-python)
|
|
36
38
|
— same domain model, same materialization rules, pointed the other way:
|
|
37
39
|
|
|
@@ -106,11 +108,22 @@ And *which packages* it sees is the working directory's
|
|
|
106
108
|
Run Python in your project, get your project's packages: `npm install`
|
|
107
109
|
next to your program is the whole setup.
|
|
108
110
|
|
|
111
|
+
## Publishing
|
|
112
|
+
|
|
113
|
+
From the Concurrent-C repo root (packs this wheel and the npm sibling):
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
./scripts/publish_bridges.sh # → out/pypi/concurrent_c_node-* (+ npm tgz)
|
|
117
|
+
./scripts/publish_bridges.sh --publish # bump patch, pack, twine + npm publish
|
|
118
|
+
```
|
|
119
|
+
|
|
109
120
|
## Measured
|
|
110
121
|
|
|
111
|
-
From
|
|
112
|
-
|
|
113
|
-
|
|
122
|
+
From `python -m cc_node.examples.bench_wire` (sources under
|
|
123
|
+
[`cc_node/examples/`](https://github.com/sreekotay/concurrent-c/blob/main/pypi/cc-node/cc_node/examples/))
|
|
124
|
+
on a 4-vCPU x86-64 box, node 22 / python 3.11
|
|
125
|
+
([`perf/baselines/cc_node_bridge_py_20260809.txt`](https://github.com/sreekotay/concurrent-c/blob/main/perf/baselines/cc_node_bridge_py_20260809.txt);
|
|
126
|
+
catalog: [`perf/baselines/README.md`](https://github.com/sreekotay/concurrent-c/blob/main/perf/baselines/README.md)):
|
|
114
127
|
|
|
115
128
|
| what | result |
|
|
116
129
|
|---|---|
|
|
@@ -127,7 +140,12 @@ future work.
|
|
|
127
140
|
|
|
128
141
|
A worked tour (builtin Node modules, chains, callbacks, thenables,
|
|
129
142
|
buffers — no npm install needed):
|
|
130
|
-
|
|
143
|
+
`python -m cc_node.examples.use_node`.
|
|
144
|
+
|
|
145
|
+
Adversarial multi-child storm (fanout, callback blizzard, shm hail,
|
|
146
|
+
teardown derby): [`stress/bridge/`](https://github.com/sreekotay/concurrent-c/tree/main/stress/bridge)
|
|
147
|
+
— `./stress/bridge/run.sh` (`CHAOS_SCALE=full` for bigger N; latency demos
|
|
148
|
+
stay in `cc_node/examples/`).
|
|
131
149
|
|
|
132
150
|
And when the hot path is YOUR code rather than an npm package, skip the
|
|
133
151
|
wire entirely: a page of Concurrent-C (or C) exports as a native module
|
|
@@ -107,9 +107,11 @@ class JsHandle:
|
|
|
107
107
|
" (closed)" if self._d.closed else "")
|
|
108
108
|
|
|
109
109
|
def __del__(self):
|
|
110
|
+
# Never nest a sync wire op from GC into an in-flight _req — that
|
|
111
|
+
# steals the outer reply (e.g. returning a callback arg handle).
|
|
110
112
|
try:
|
|
111
113
|
if not self._d.closed:
|
|
112
|
-
self._d.
|
|
114
|
+
self._d._queue_release(self._h)
|
|
113
115
|
except Exception:
|
|
114
116
|
pass
|
|
115
117
|
|
|
@@ -137,6 +139,11 @@ class Bridge:
|
|
|
137
139
|
self._cbs = {}
|
|
138
140
|
self._ncb = 1
|
|
139
141
|
self._shm_out = []
|
|
142
|
+
self._depth = 0
|
|
143
|
+
self._parked = {}
|
|
144
|
+
self._pending_release = []
|
|
145
|
+
self._close_pending = False
|
|
146
|
+
self._destroy_done = False
|
|
140
147
|
_live.append(self)
|
|
141
148
|
|
|
142
149
|
# ---- wire ----
|
|
@@ -146,6 +153,56 @@ class Bridge:
|
|
|
146
153
|
self._p.stdin.write(line.encode("utf-8"))
|
|
147
154
|
self._p.stdin.flush()
|
|
148
155
|
|
|
156
|
+
def _queue_release(self, hid):
|
|
157
|
+
self._pending_release.append(hid)
|
|
158
|
+
if self._depth == 0:
|
|
159
|
+
self._flush_releases()
|
|
160
|
+
|
|
161
|
+
def _flush_releases(self):
|
|
162
|
+
while self._pending_release and not self.closed:
|
|
163
|
+
hid = self._pending_release.pop(0)
|
|
164
|
+
try:
|
|
165
|
+
self._req("release", h=hid)
|
|
166
|
+
except Exception:
|
|
167
|
+
pass
|
|
168
|
+
|
|
169
|
+
def _flush_shm(self):
|
|
170
|
+
# The child unlinks spill files as it decodes; this sweep only
|
|
171
|
+
# matters when it died first (ENOENT is the normal case).
|
|
172
|
+
for path in self._shm_out:
|
|
173
|
+
try:
|
|
174
|
+
os.unlink(path)
|
|
175
|
+
except OSError:
|
|
176
|
+
pass
|
|
177
|
+
del self._shm_out[:]
|
|
178
|
+
|
|
179
|
+
def _take_reply(self, msg):
|
|
180
|
+
if "e" in msg:
|
|
181
|
+
raise JsError(msg["e"])
|
|
182
|
+
return self._decode_result(msg)
|
|
183
|
+
|
|
184
|
+
def _wait_reply(self, rid):
|
|
185
|
+
parked = self._parked.pop(rid, None)
|
|
186
|
+
if parked is not None:
|
|
187
|
+
return self._take_reply(parked)
|
|
188
|
+
while True:
|
|
189
|
+
line = self._p.stdout.readline()
|
|
190
|
+
if not line:
|
|
191
|
+
self.closed = True
|
|
192
|
+
raise JsError("cc-node: the node child exited")
|
|
193
|
+
msg = json.loads(line)
|
|
194
|
+
if "cb" in msg:
|
|
195
|
+
self._serve_callback(msg)
|
|
196
|
+
continue
|
|
197
|
+
mid = msg.get("id")
|
|
198
|
+
if mid == rid:
|
|
199
|
+
return self._take_reply(msg)
|
|
200
|
+
if mid is not None:
|
|
201
|
+
# Nested _req (GC release, etc.) can overtake; park by id.
|
|
202
|
+
self._parked[mid] = msg
|
|
203
|
+
continue
|
|
204
|
+
raise JsError("cc-node: protocol violation (unexpected reply)")
|
|
205
|
+
|
|
149
206
|
def _req(self, op, **kw):
|
|
150
207
|
if self.closed:
|
|
151
208
|
raise JsError("cc-node: bridge is closed")
|
|
@@ -153,35 +210,22 @@ class Bridge:
|
|
|
153
210
|
self._nid += 1
|
|
154
211
|
kw["id"] = rid
|
|
155
212
|
kw["op"] = op
|
|
213
|
+
self._depth += 1
|
|
156
214
|
try:
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
line = self._p.stdout.readline()
|
|
164
|
-
if not line:
|
|
165
|
-
self.closed = True
|
|
166
|
-
raise JsError("cc-node: the node child exited")
|
|
167
|
-
msg = json.loads(line)
|
|
168
|
-
if "cb" in msg:
|
|
169
|
-
self._serve_callback(msg)
|
|
170
|
-
continue
|
|
171
|
-
if msg.get("id") == rid:
|
|
172
|
-
if "e" in msg:
|
|
173
|
-
raise JsError(msg["e"])
|
|
174
|
-
return self._decode_result(msg)
|
|
175
|
-
raise JsError("cc-node: protocol violation (unexpected reply)")
|
|
215
|
+
try:
|
|
216
|
+
self._send(kw)
|
|
217
|
+
except (BrokenPipeError, ValueError):
|
|
218
|
+
self.closed = True
|
|
219
|
+
raise JsError("cc-node: the node child exited") from None
|
|
220
|
+
return self._wait_reply(rid)
|
|
176
221
|
finally:
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
del self._shm_out[:]
|
|
222
|
+
self._depth -= 1
|
|
223
|
+
if self._depth == 0:
|
|
224
|
+
self._flush_shm()
|
|
225
|
+
if self._close_pending:
|
|
226
|
+
self._finish_destroy()
|
|
227
|
+
else:
|
|
228
|
+
self._flush_releases()
|
|
185
229
|
|
|
186
230
|
def _serve_callback(self, msg):
|
|
187
231
|
fn = self._cbs.get(msg["cb"])
|
|
@@ -309,13 +353,32 @@ class Bridge:
|
|
|
309
353
|
return self._req("stats")
|
|
310
354
|
|
|
311
355
|
def destroy(self):
|
|
312
|
-
|
|
356
|
+
"""Idempotent teardown. Nested destroy (e.g. from a Python
|
|
357
|
+
callback while the broker waits on cbr) defers the farewell
|
|
358
|
+
close until the in-flight wire op unwinds — nesting close into
|
|
359
|
+
the cbr slot hangs the child."""
|
|
360
|
+
if self._destroy_done:
|
|
361
|
+
return
|
|
362
|
+
if self._depth > 0:
|
|
363
|
+
self.closed = True
|
|
364
|
+
self._close_pending = True
|
|
365
|
+
return
|
|
366
|
+
self._finish_destroy()
|
|
367
|
+
|
|
368
|
+
def _finish_destroy(self):
|
|
369
|
+
if self._destroy_done:
|
|
313
370
|
return
|
|
371
|
+
self._destroy_done = True
|
|
372
|
+
self._close_pending = False
|
|
373
|
+
self.closed = True
|
|
314
374
|
try:
|
|
315
|
-
self.
|
|
316
|
-
|
|
375
|
+
if self._p.poll() is None and self._p.stdin \
|
|
376
|
+
and not self._p.stdin.closed:
|
|
377
|
+
rid = self._nid
|
|
378
|
+
self._nid += 1
|
|
379
|
+
self._send({"id": rid, "op": "close"})
|
|
380
|
+
except Exception:
|
|
317
381
|
pass
|
|
318
|
-
self.closed = True
|
|
319
382
|
try:
|
|
320
383
|
self._p.stdin.close()
|
|
321
384
|
except Exception:
|
|
@@ -323,7 +386,10 @@ class Bridge:
|
|
|
323
386
|
try:
|
|
324
387
|
self._p.wait(timeout=5)
|
|
325
388
|
except Exception:
|
|
326
|
-
|
|
389
|
+
try:
|
|
390
|
+
self._p.kill()
|
|
391
|
+
except Exception:
|
|
392
|
+
pass
|
|
327
393
|
if self in _live:
|
|
328
394
|
_live.remove(self)
|
|
329
395
|
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""The cc-node wire, measured. RESULT lines are machine-comparable.
|
|
2
|
+
|
|
3
|
+
python -m cc_node.examples.bench_wire
|
|
4
|
+
"""
|
|
5
|
+
import array
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
import cc_node
|
|
9
|
+
|
|
10
|
+
t0 = time.perf_counter()
|
|
11
|
+
js = cc_node.create()
|
|
12
|
+
js.eval("1")
|
|
13
|
+
print("RESULT spawn_ms %d" % round((time.perf_counter() - t0) * 1000))
|
|
14
|
+
|
|
15
|
+
f = js.eval("(x) => x")
|
|
16
|
+
f(1)
|
|
17
|
+
t0 = time.perf_counter()
|
|
18
|
+
for i in range(500):
|
|
19
|
+
f(i)
|
|
20
|
+
print("RESULT rtt_us %d" % round((time.perf_counter() - t0) / 500 * 1e6))
|
|
21
|
+
|
|
22
|
+
g = js.eval("(cb) => cb(21) * 2")
|
|
23
|
+
g(lambda x: x + 1)
|
|
24
|
+
t0 = time.perf_counter()
|
|
25
|
+
for _ in range(200):
|
|
26
|
+
g(lambda x: x + 1)
|
|
27
|
+
print("RESULT callback_roundtrip_us %d"
|
|
28
|
+
% round((time.perf_counter() - t0) / 200 * 1e6))
|
|
29
|
+
|
|
30
|
+
big = array.array("d", [float(i % 97) for i in range(1 << 20)]) # 8MB
|
|
31
|
+
ln = js.eval("(a) => a.length")
|
|
32
|
+
ln(big)
|
|
33
|
+
t0 = time.perf_counter()
|
|
34
|
+
for _ in range(10):
|
|
35
|
+
ln(big)
|
|
36
|
+
print("RESULT bulk_8mb_shm_ms %.1f" % ((time.perf_counter() - t0) / 10 * 1000))
|
|
37
|
+
|
|
38
|
+
biglist = [float(i % 97) for i in range(1 << 20)]
|
|
39
|
+
ln(biglist)
|
|
40
|
+
t0 = time.perf_counter()
|
|
41
|
+
for _ in range(3):
|
|
42
|
+
ln(biglist)
|
|
43
|
+
print("RESULT bulk_8mb_json_list_ms %d"
|
|
44
|
+
% round((time.perf_counter() - t0) / 3 * 1000))
|
|
45
|
+
|
|
46
|
+
js.destroy()
|
|
47
|
+
print("done")
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""cc-node in one sitting: builtin Node modules (no npm install needed),
|
|
2
|
+
chains, callbacks both ways, and async-for-free.
|
|
3
|
+
|
|
4
|
+
python -m cc_node.examples.use_node
|
|
5
|
+
"""
|
|
6
|
+
import cc_node
|
|
7
|
+
|
|
8
|
+
with cc_node.create() as js:
|
|
9
|
+
# Builtin modules: attribute access is property lookup, calls are calls.
|
|
10
|
+
path = js.require("path")
|
|
11
|
+
print("join :", path.join("a", "b", "c.txt"))
|
|
12
|
+
|
|
13
|
+
crypto = js.require("crypto")
|
|
14
|
+
print("sha256 :", crypto.createHash("sha256")
|
|
15
|
+
.update("cc-node").digest("hex")[:16], "...")
|
|
16
|
+
|
|
17
|
+
# eval for a quick lambda; a Python callable crosses as a JS function
|
|
18
|
+
# (JS conventions apply: Array.map passes value, index, array).
|
|
19
|
+
mapped = js.eval("(f) => [1, 2, 3].map(f)")(lambda x, *rest: x * 10)
|
|
20
|
+
print("callback :", mapped)
|
|
21
|
+
|
|
22
|
+
# Async is free: thenables are awaited in the child before the reply.
|
|
23
|
+
fetchish = js.eval("async (x) => { return { doubled: x * 2 } }")
|
|
24
|
+
print("thenable :", fetchish(21))
|
|
25
|
+
|
|
26
|
+
# Typed buffers cross as typed arrays (big ones via shared memory);
|
|
27
|
+
# results come back as numpy arrays when numpy is installed.
|
|
28
|
+
total = js.eval("(a) => a.reduce((s, x) => s + x, 0)")
|
|
29
|
+
import array
|
|
30
|
+
print("buffer sum:", total(array.array("d", [1.5, 2.5, 3.0])))
|
|
31
|
+
|
|
32
|
+
print("handles :", js.stats())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: concurrent-c-node
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: JavaScript and npm packages from Python over the Concurrent-C bridge: one spawned Node child per domain, host-controlled lifetime.
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/sreekotay/concurrent-c
|
|
@@ -40,9 +40,11 @@ array in **9ms** where the same values as a JSON list take 583ms.
|
|
|
40
40
|
|
|
41
41
|
```
|
|
42
42
|
pip install concurrent-c-node # needs node on PATH (or point at one)
|
|
43
|
+
python -m cc_node.examples.use_node
|
|
44
|
+
python -m cc_node.examples.bench_wire
|
|
43
45
|
```
|
|
44
46
|
|
|
45
|
-
Import stays `import cc_node`. The mirror of
|
|
47
|
+
Import stays `import cc_node`. Examples ship in the wheel. The mirror of
|
|
46
48
|
[`concurrent-c-python`](https://github.com/sreekotay/concurrent-c/tree/main/npm/cc-python)
|
|
47
49
|
— same domain model, same materialization rules, pointed the other way:
|
|
48
50
|
|
|
@@ -117,11 +119,22 @@ And *which packages* it sees is the working directory's
|
|
|
117
119
|
Run Python in your project, get your project's packages: `npm install`
|
|
118
120
|
next to your program is the whole setup.
|
|
119
121
|
|
|
122
|
+
## Publishing
|
|
123
|
+
|
|
124
|
+
From the Concurrent-C repo root (packs this wheel and the npm sibling):
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
./scripts/publish_bridges.sh # → out/pypi/concurrent_c_node-* (+ npm tgz)
|
|
128
|
+
./scripts/publish_bridges.sh --publish # bump patch, pack, twine + npm publish
|
|
129
|
+
```
|
|
130
|
+
|
|
120
131
|
## Measured
|
|
121
132
|
|
|
122
|
-
From
|
|
123
|
-
|
|
124
|
-
|
|
133
|
+
From `python -m cc_node.examples.bench_wire` (sources under
|
|
134
|
+
[`cc_node/examples/`](https://github.com/sreekotay/concurrent-c/blob/main/pypi/cc-node/cc_node/examples/))
|
|
135
|
+
on a 4-vCPU x86-64 box, node 22 / python 3.11
|
|
136
|
+
([`perf/baselines/cc_node_bridge_py_20260809.txt`](https://github.com/sreekotay/concurrent-c/blob/main/perf/baselines/cc_node_bridge_py_20260809.txt);
|
|
137
|
+
catalog: [`perf/baselines/README.md`](https://github.com/sreekotay/concurrent-c/blob/main/perf/baselines/README.md)):
|
|
125
138
|
|
|
126
139
|
| what | result |
|
|
127
140
|
|---|---|
|
|
@@ -138,7 +151,12 @@ future work.
|
|
|
138
151
|
|
|
139
152
|
A worked tour (builtin Node modules, chains, callbacks, thenables,
|
|
140
153
|
buffers — no npm install needed):
|
|
141
|
-
|
|
154
|
+
`python -m cc_node.examples.use_node`.
|
|
155
|
+
|
|
156
|
+
Adversarial multi-child storm (fanout, callback blizzard, shm hail,
|
|
157
|
+
teardown derby): [`stress/bridge/`](https://github.com/sreekotay/concurrent-c/tree/main/stress/bridge)
|
|
158
|
+
— `./stress/bridge/run.sh` (`CHAOS_SCALE=full` for bigger N; latency demos
|
|
159
|
+
stay in `cc_node/examples/`).
|
|
142
160
|
|
|
143
161
|
And when the hot path is YOUR code rather than an npm package, skip the
|
|
144
162
|
wire entirely: a page of Concurrent-C (or C) exports as a native module
|
|
@@ -2,6 +2,9 @@ README.md
|
|
|
2
2
|
pyproject.toml
|
|
3
3
|
cc_node/__init__.py
|
|
4
4
|
cc_node/broker.cjs
|
|
5
|
+
cc_node/examples/__init__.py
|
|
6
|
+
cc_node/examples/bench_wire.py
|
|
7
|
+
cc_node/examples/use_node.py
|
|
5
8
|
concurrent_c_node.egg-info/PKG-INFO
|
|
6
9
|
concurrent_c_node.egg-info/SOURCES.txt
|
|
7
10
|
concurrent_c_node.egg-info/dependency_links.txt
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "concurrent-c-node"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "JavaScript and npm packages from Python over the Concurrent-C bridge: one spawned Node child per domain, host-controlled lifetime."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -16,7 +16,8 @@ Repository = "https://github.com/sreekotay/concurrent-c"
|
|
|
16
16
|
Documentation = "https://github.com/sreekotay/concurrent-c/blob/main/pypi/cc-node/README.md"
|
|
17
17
|
|
|
18
18
|
[tool.setuptools]
|
|
19
|
-
packages = ["cc_node"]
|
|
19
|
+
packages = ["cc_node", "cc_node.examples"]
|
|
20
20
|
|
|
21
21
|
[tool.setuptools.package-data]
|
|
22
22
|
cc_node = ["broker.cjs"]
|
|
23
|
+
"cc_node.examples" = ["*.py"]
|
|
File without changes
|
{concurrent_c_node-0.2.0 → concurrent_c_node-0.3.0}/concurrent_c_node.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{concurrent_c_node-0.2.0 → concurrent_c_node-0.3.0}/concurrent_c_node.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|