QuLab 2.2.4__cp312-cp312-macosx_10_9_universal2.whl → 2.2.6__cp312-cp312-macosx_10_9_universal2.whl
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.
- {QuLab-2.2.4.dist-info → QuLab-2.2.6.dist-info}/METADATA +1 -1
- {QuLab-2.2.4.dist-info → QuLab-2.2.6.dist-info}/RECORD +14 -14
- qulab/fun.cpython-312-darwin.so +0 -0
- qulab/scan/query.py +14 -6
- qulab/scan/record.py +93 -57
- qulab/scan/scan.py +25 -16
- qulab/scan/server.py +63 -13
- qulab/scan/space.py +2 -0
- qulab/sys/rpc/zmq_socket.py +6 -1
- qulab/version.py +1 -1
- {QuLab-2.2.4.dist-info → QuLab-2.2.6.dist-info}/LICENSE +0 -0
- {QuLab-2.2.4.dist-info → QuLab-2.2.6.dist-info}/WHEEL +0 -0
- {QuLab-2.2.4.dist-info → QuLab-2.2.6.dist-info}/entry_points.txt +0 -0
- {QuLab-2.2.4.dist-info → QuLab-2.2.6.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
qulab/__init__.py,sha256=P-Mx2p4TVmL91SoxoeXcj8Qm0x4xUf5Q_FLk0Yc_gIQ,138
|
|
2
2
|
qulab/__main__.py,sha256=ZC1NKaoxKyy60DaCfB8vYnB1z3RXQ2j8E1sRZ4A8sXE,428
|
|
3
|
-
qulab/fun.cpython-312-darwin.so,sha256=
|
|
4
|
-
qulab/version.py,sha256=
|
|
3
|
+
qulab/fun.cpython-312-darwin.so,sha256=u0mgQut8kL1WBGiMQmthONZfWRJ-hDJ_pQ1YD5GhwMw,159632
|
|
4
|
+
qulab/version.py,sha256=CsrswO-ECCDHSY48Nv5lOOdRgL8EGAixBOHDf7PkRZA,21
|
|
5
5
|
qulab/monitor/__init__.py,sha256=nTHelnDpxRS_fl_B38TsN0njgq8eVTEz9IAnN3NbDlM,42
|
|
6
6
|
qulab/monitor/__main__.py,sha256=w3yUcqq195LzSnXTkQcuC1RSFRhy4oQ_PEBmucXguME,97
|
|
7
7
|
qulab/monitor/config.py,sha256=fQ5JcsMApKc1UwANEnIvbDQZl8uYW0tle92SaYtX9lI,744
|
|
@@ -17,11 +17,11 @@ qulab/scan/curd.py,sha256=thq_qfi3qng3Zx-1uhNG64IQhGCuum_LR4MOKnS8cDI,6896
|
|
|
17
17
|
qulab/scan/expression.py,sha256=-aTYbjFQNI1mwOcoSBztqhKfGJpu_n4a1QnWro_xnTU,15694
|
|
18
18
|
qulab/scan/models.py,sha256=5Jpo25WGMWs0GtLzYLsWO61G3-FFYx5BHhBr2b6rOTE,17681
|
|
19
19
|
qulab/scan/optimize.py,sha256=vErjRTCtn2MwMF5Xyhs1P4gHF2IFHv_EqxsUvH_4y7k,2287
|
|
20
|
-
qulab/scan/query.py,sha256
|
|
21
|
-
qulab/scan/record.py,sha256=
|
|
22
|
-
qulab/scan/scan.py,sha256=
|
|
23
|
-
qulab/scan/server.py,sha256=
|
|
24
|
-
qulab/scan/space.py,sha256=
|
|
20
|
+
qulab/scan/query.py,sha256=-5uHMhXSyGovK1oy_uUbGVEbRFzaMBkP78ZMNfI3jD0,11809
|
|
21
|
+
qulab/scan/record.py,sha256=xgmhtL9l019HYHOHvyzK1vxqagGam51rAM7sj9ZWm5U,21103
|
|
22
|
+
qulab/scan/scan.py,sha256=YPGeuBwxepwmKvz3HE0X5euHqPQGSc9NUGEPEiPRiso,34884
|
|
23
|
+
qulab/scan/server.py,sha256=u6in_8-AfcCA4pGAolNR_2emlewGdc3bN6c0pDygBWY,14158
|
|
24
|
+
qulab/scan/space.py,sha256=jDmFY2FcYe-Qcp16YBhAEdTKibOAsHQUnpDrpcPhvzg,5279
|
|
25
25
|
qulab/scan/utils.py,sha256=Pg_tCf3SUKTiPSBqb6Enkgx4bAyQJAkDGe9uYys1xVU,3613
|
|
26
26
|
qulab/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
27
|
qulab/storage/__main__.py,sha256=3emxxRry8BB0m8hUZvJ_oBqkPy7ksV7flHB_KEDXZuI,1692
|
|
@@ -70,7 +70,7 @@ qulab/sys/rpc/server.py,sha256=e3R0gwOHpLEkSp7Tb43FMSDvqSG-pjrkskdISKQRseE,713
|
|
|
70
70
|
qulab/sys/rpc/socket.py,sha256=e3R0gwOHpLEkSp7Tb43FMSDvqSG-pjrkskdISKQRseE,713
|
|
71
71
|
qulab/sys/rpc/utils.py,sha256=6YGFOkY7o09lkA_I1FIP9_1Up3k2F1KOkftvu0_8lxo,594
|
|
72
72
|
qulab/sys/rpc/worker.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
|
-
qulab/sys/rpc/zmq_socket.py,sha256=
|
|
73
|
+
qulab/sys/rpc/zmq_socket.py,sha256=2uc9MjCRUwWm6iPmi2VGnOYNf9yWFSUzEVYrx0jZvPU,8272
|
|
74
74
|
qulab/visualization/__init__.py,sha256=26cuHt3QIJXUb3VaMxlJx3IQTOUVJFKlYBZr7WMP53M,6129
|
|
75
75
|
qulab/visualization/__main__.py,sha256=9zKK3yZFy0leU40ou6BpRC1Fsetfc1gjjFzIZYIwP6Y,1639
|
|
76
76
|
qulab/visualization/_autoplot.py,sha256=jddg40dX48Wd8G6NLFA_Kf7z1QxdrZBDS99Xx2GLMqs,14099
|
|
@@ -78,9 +78,9 @@ qulab/visualization/plot_layout.py,sha256=clNw9QjE_kVNpIIx2Ob4YhAz2fucPGMuzkoIrO
|
|
|
78
78
|
qulab/visualization/plot_seq.py,sha256=lphYF4VhkEdc_wWr1kFBwrx2yujkyFPFaJ3pjr61awI,2693
|
|
79
79
|
qulab/visualization/qdat.py,sha256=ZeevBYWkzbww4xZnsjHhw7wRorJCBzbG0iEu-XQB4EA,5735
|
|
80
80
|
qulab/visualization/widgets.py,sha256=6KkiTyQ8J-ei70LbPQZAK35wjktY47w2IveOa682ftA,3180
|
|
81
|
-
QuLab-2.2.
|
|
82
|
-
QuLab-2.2.
|
|
83
|
-
QuLab-2.2.
|
|
84
|
-
QuLab-2.2.
|
|
85
|
-
QuLab-2.2.
|
|
86
|
-
QuLab-2.2.
|
|
81
|
+
QuLab-2.2.6.dist-info/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
|
|
82
|
+
QuLab-2.2.6.dist-info/METADATA,sha256=4vOBx495seNQlHygPaIrLKr2y7C5NtMIhPzwUnnI2r8,3510
|
|
83
|
+
QuLab-2.2.6.dist-info/WHEEL,sha256=aK27B_a3TQKBFhN_ATCfuFR4pBRqHlzwr7HpZ6iA79M,115
|
|
84
|
+
QuLab-2.2.6.dist-info/entry_points.txt,sha256=ohBzutEnQimP_BZWiuXdSliu4QAYSHHcN0PZD8c7ZCY,46
|
|
85
|
+
QuLab-2.2.6.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
|
|
86
|
+
QuLab-2.2.6.dist-info/RECORD,,
|
qulab/fun.cpython-312-darwin.so
CHANGED
|
Binary file
|
qulab/scan/query.py
CHANGED
|
@@ -16,9 +16,13 @@ from .scan import default_server
|
|
|
16
16
|
from .server import get_local_record
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def get_record(id,
|
|
19
|
+
def get_record(id,
|
|
20
|
+
database=default_server,
|
|
21
|
+
socket=None,
|
|
22
|
+
session=None) -> Record:
|
|
20
23
|
if isinstance(database, str) and database.startswith('tcp://'):
|
|
21
|
-
with ZMQContextManager(zmq.DEALER, connect=database
|
|
24
|
+
with ZMQContextManager(zmq.DEALER, connect=database,
|
|
25
|
+
socket=socket) as socket:
|
|
22
26
|
socket.send_pyobj({
|
|
23
27
|
'method': 'record_description',
|
|
24
28
|
'record_id': id
|
|
@@ -29,12 +33,16 @@ def get_record(id, database=default_server) -> Record:
|
|
|
29
33
|
d.id = id
|
|
30
34
|
d.database = database
|
|
31
35
|
d._file = None
|
|
36
|
+
d._sock = socket
|
|
32
37
|
return d
|
|
33
38
|
else:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
if session is None:
|
|
40
|
+
db_file = Path(database) / 'data.db'
|
|
41
|
+
engine = create_engine(f'sqlite:///{db_file}')
|
|
42
|
+
Session = sessionmaker(bind=engine)
|
|
43
|
+
with Session() as session:
|
|
44
|
+
return get_local_record(session, id, database)
|
|
45
|
+
else:
|
|
38
46
|
return get_local_record(session, id, database)
|
|
39
47
|
|
|
40
48
|
|
qulab/scan/record.py
CHANGED
|
@@ -56,6 +56,7 @@ class BufferList():
|
|
|
56
56
|
self._slice = slice
|
|
57
57
|
self._lock = Lock()
|
|
58
58
|
self._data_id = None
|
|
59
|
+
self._sock = None
|
|
59
60
|
|
|
60
61
|
def __repr__(self):
|
|
61
62
|
return f"<BufferList: shape={self.shape}, lu={self.lu}, rd={self.rd}, slice={self._slice}>"
|
|
@@ -82,6 +83,7 @@ class BufferList():
|
|
|
82
83
|
self._slice = None
|
|
83
84
|
self._lock = Lock()
|
|
84
85
|
self._data_id = None
|
|
86
|
+
self._sock = None
|
|
85
87
|
|
|
86
88
|
@property
|
|
87
89
|
def shape(self):
|
|
@@ -115,7 +117,8 @@ class BufferList():
|
|
|
115
117
|
self.inner_shape = value.shape
|
|
116
118
|
elif self.inner_shape != value.shape:
|
|
117
119
|
self.inner_shape = ()
|
|
118
|
-
self.
|
|
120
|
+
with self._lock:
|
|
121
|
+
self._list.append((pos, value))
|
|
119
122
|
if len(self._list) > 1000:
|
|
120
123
|
self.flush()
|
|
121
124
|
|
|
@@ -155,15 +158,32 @@ class BufferList():
|
|
|
155
158
|
yield pos, value
|
|
156
159
|
else:
|
|
157
160
|
server, record_id, key = self._data_id
|
|
158
|
-
with ZMQContextManager(zmq.DEALER,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
161
|
+
with ZMQContextManager(zmq.DEALER,
|
|
162
|
+
connect=server,
|
|
163
|
+
socket=self._sock) as socket:
|
|
164
|
+
iter_id = b''
|
|
165
|
+
start = 0
|
|
166
|
+
try:
|
|
167
|
+
while True:
|
|
168
|
+
socket.send_pyobj({
|
|
169
|
+
'method': 'bufferlist_iter',
|
|
170
|
+
'record_id': record_id,
|
|
171
|
+
'iter_id': iter_id,
|
|
172
|
+
'key': key,
|
|
173
|
+
'slice': self._slice,
|
|
174
|
+
'start': start
|
|
175
|
+
})
|
|
176
|
+
iter_id, lst, finished = socket.recv_pyobj()
|
|
177
|
+
start += len(lst)
|
|
178
|
+
yield from lst
|
|
179
|
+
if finished:
|
|
180
|
+
break
|
|
181
|
+
finally:
|
|
182
|
+
if iter_id:
|
|
183
|
+
socket.send_pyobj({
|
|
184
|
+
'method': 'bufferlist_iter_exit',
|
|
185
|
+
'iter_id': iter_id
|
|
186
|
+
})
|
|
167
187
|
|
|
168
188
|
def value(self):
|
|
169
189
|
d = []
|
|
@@ -184,7 +204,7 @@ class BufferList():
|
|
|
184
204
|
d.append(value)
|
|
185
205
|
return p, d
|
|
186
206
|
|
|
187
|
-
def
|
|
207
|
+
def toarray(self):
|
|
188
208
|
pos, data = self.items()
|
|
189
209
|
if self._slice:
|
|
190
210
|
pos = np.asarray(pos)
|
|
@@ -278,7 +298,7 @@ class BufferList():
|
|
|
278
298
|
def __getitem__(self, slice_tuple: slice | EllipsisType
|
|
279
299
|
| tuple[slice | int | EllipsisType, ...]):
|
|
280
300
|
self._slice, contract, reversed = self._full_slice(slice_tuple)
|
|
281
|
-
ret = self.
|
|
301
|
+
ret = self.toarray()
|
|
282
302
|
slices = []
|
|
283
303
|
for i, s in enumerate(self._slice):
|
|
284
304
|
if i in contract:
|
|
@@ -303,6 +323,15 @@ class Record():
|
|
|
303
323
|
self._pos = []
|
|
304
324
|
self._last_vars = set()
|
|
305
325
|
self._file = None
|
|
326
|
+
self._sock = None
|
|
327
|
+
|
|
328
|
+
for name, value in self.description['intrinsic_loops'].items():
|
|
329
|
+
self._items[name] = value
|
|
330
|
+
|
|
331
|
+
for level, range_list in description['loops'].items():
|
|
332
|
+
for name, iterable in range_list:
|
|
333
|
+
if name in self.description['independent_variables']:
|
|
334
|
+
self._items[name] = iterable
|
|
306
335
|
|
|
307
336
|
if self.is_local_record():
|
|
308
337
|
self.database = Path(self.database)
|
|
@@ -324,6 +353,7 @@ class Record():
|
|
|
324
353
|
self._last_vars = set()
|
|
325
354
|
self.database = None
|
|
326
355
|
self._file = None
|
|
356
|
+
self._sock = None
|
|
327
357
|
|
|
328
358
|
@property
|
|
329
359
|
def axis(self):
|
|
@@ -337,7 +367,8 @@ class Record():
|
|
|
337
367
|
return cls(config_id)
|
|
338
368
|
if self.is_remote_record():
|
|
339
369
|
with ZMQContextManager(zmq.DEALER,
|
|
340
|
-
connect=self.database
|
|
370
|
+
connect=self.database,
|
|
371
|
+
socket=self._sock) as socket:
|
|
341
372
|
socket.send_pyobj({
|
|
342
373
|
'method': 'config_get',
|
|
343
374
|
'config_id': config_id
|
|
@@ -351,6 +382,31 @@ class Record():
|
|
|
351
382
|
session.commit()
|
|
352
383
|
return cls(config)
|
|
353
384
|
|
|
385
|
+
def scripts(self, session=None):
|
|
386
|
+
scripts = self.description['entry']['scripts']
|
|
387
|
+
if isinstance(scripts, list):
|
|
388
|
+
return scripts
|
|
389
|
+
else:
|
|
390
|
+
cell_id = scripts
|
|
391
|
+
|
|
392
|
+
if self.is_remote_record():
|
|
393
|
+
with ZMQContextManager(zmq.DEALER,
|
|
394
|
+
connect=self.database,
|
|
395
|
+
socket=self._sock) as socket:
|
|
396
|
+
socket.send_pyobj({
|
|
397
|
+
'method': 'notebook_history',
|
|
398
|
+
'cell_id': cell_id
|
|
399
|
+
})
|
|
400
|
+
return socket.recv_pyobj()
|
|
401
|
+
elif self.is_local_record():
|
|
402
|
+
from .models import Cell
|
|
403
|
+
assert session is not None, "session is required for local record"
|
|
404
|
+
cell = session.get(Cell, cell_id)
|
|
405
|
+
return [
|
|
406
|
+
cell.input.text
|
|
407
|
+
for cell in cell.notebook.cells[1:cell.index + 2]
|
|
408
|
+
]
|
|
409
|
+
|
|
354
410
|
def is_local_record(self):
|
|
355
411
|
return not self.is_cache_record() and not self.is_remote_record()
|
|
356
412
|
|
|
@@ -365,15 +421,13 @@ class Record():
|
|
|
365
421
|
self.flush()
|
|
366
422
|
|
|
367
423
|
def __getitem__(self, key):
|
|
368
|
-
|
|
369
|
-
if isinstance(ret, Space):
|
|
370
|
-
ret = ret.toarray()
|
|
371
|
-
return ret
|
|
424
|
+
return self.get(key, buffer_to_array=True)
|
|
372
425
|
|
|
373
|
-
def get(self, key, default=_not_given, buffer_to_array=False
|
|
426
|
+
def get(self, key, default=_not_given, buffer_to_array=False):
|
|
374
427
|
if self.is_remote_record():
|
|
375
428
|
with ZMQContextManager(zmq.DEALER,
|
|
376
|
-
connect=self.database
|
|
429
|
+
connect=self.database,
|
|
430
|
+
socket=self._sock) as socket:
|
|
377
431
|
socket.send_pyobj({
|
|
378
432
|
'method': 'record_getitem',
|
|
379
433
|
'record_id': self.id,
|
|
@@ -381,20 +435,14 @@ class Record():
|
|
|
381
435
|
})
|
|
382
436
|
ret = socket.recv_pyobj()
|
|
383
437
|
if isinstance(ret, BufferList):
|
|
438
|
+
ret._data_id = self.database, self.id, key
|
|
439
|
+
ret._sock = socket
|
|
384
440
|
if buffer_to_array:
|
|
385
|
-
|
|
386
|
-
'method': 'bufferlist_slice',
|
|
387
|
-
'record_id': self.id,
|
|
388
|
-
'key': key,
|
|
389
|
-
'slice': slice
|
|
390
|
-
})
|
|
391
|
-
lst = socket.recv_pyobj()
|
|
392
|
-
ret._list = lst
|
|
393
|
-
ret._slice = slice
|
|
394
|
-
return ret.array()
|
|
441
|
+
return ret.toarray()
|
|
395
442
|
else:
|
|
396
|
-
ret._data_id = self.database, self.id, key
|
|
397
443
|
return ret
|
|
444
|
+
elif isinstance(ret, Space) and buffer_to_array:
|
|
445
|
+
return ret.toarray()
|
|
398
446
|
else:
|
|
399
447
|
return ret
|
|
400
448
|
else:
|
|
@@ -407,7 +455,12 @@ class Record():
|
|
|
407
455
|
d.file = self._file.parent.parent.parent.parent / d.file
|
|
408
456
|
d._slice = slice
|
|
409
457
|
if buffer_to_array:
|
|
410
|
-
return d.
|
|
458
|
+
return d.toarray()
|
|
459
|
+
else:
|
|
460
|
+
return d
|
|
461
|
+
elif isinstance(d, Space):
|
|
462
|
+
if buffer_to_array:
|
|
463
|
+
return d.toarray()
|
|
411
464
|
else:
|
|
412
465
|
return d
|
|
413
466
|
else:
|
|
@@ -416,7 +469,8 @@ class Record():
|
|
|
416
469
|
def keys(self):
|
|
417
470
|
if self.is_remote_record():
|
|
418
471
|
with ZMQContextManager(zmq.DEALER,
|
|
419
|
-
connect=self.database
|
|
472
|
+
connect=self.database,
|
|
473
|
+
socket=self._sock) as socket:
|
|
420
474
|
socket.send_pyobj({
|
|
421
475
|
'method': 'record_keys',
|
|
422
476
|
'record_id': self.id
|
|
@@ -483,7 +537,8 @@ class Record():
|
|
|
483
537
|
def delete(self):
|
|
484
538
|
if self.is_remote_record():
|
|
485
539
|
with ZMQContextManager(zmq.DEALER,
|
|
486
|
-
connect=self.database
|
|
540
|
+
connect=self.database,
|
|
541
|
+
socket=self._sock) as socket:
|
|
487
542
|
socket.send_pyobj({
|
|
488
543
|
'method': 'record_delete',
|
|
489
544
|
'record_id': self.id
|
|
@@ -516,36 +571,17 @@ class Record():
|
|
|
516
571
|
with z.open('record.pkl', 'w') as f:
|
|
517
572
|
self.description['entry']['scripts'] = self.scripts()
|
|
518
573
|
dill.dump((self.description, items), f)
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
scripts = self.description['entry']['scripts']
|
|
522
|
-
if isinstance(scripts, list):
|
|
523
|
-
return scripts
|
|
524
|
-
else:
|
|
525
|
-
cell_id = scripts
|
|
526
|
-
|
|
527
|
-
if self.is_remote_record():
|
|
528
|
-
with ZMQContextManager(zmq.DEALER,
|
|
529
|
-
connect=self.database) as socket:
|
|
530
|
-
socket.send_pyobj({
|
|
531
|
-
'method': 'notebook_history',
|
|
532
|
-
'cell_id': cell_id
|
|
533
|
-
})
|
|
534
|
-
return socket.recv_pyobj()
|
|
535
|
-
elif self.is_local_record():
|
|
536
|
-
from .models import Cell
|
|
537
|
-
assert session is not None, "session is required for local record"
|
|
538
|
-
cell = session.get(Cell, cell_id)
|
|
539
|
-
return [
|
|
540
|
-
cell.input.text
|
|
541
|
-
for cell in cell.notebook.cells[1:cell.index + 2]
|
|
542
|
-
]
|
|
574
|
+
with z.open('config.pkl', 'w') as f:
|
|
575
|
+
f.write(dill.dumps(self.config()))
|
|
543
576
|
|
|
544
577
|
@classmethod
|
|
545
578
|
def load(cls, file: str):
|
|
546
579
|
with zipfile.ZipFile(file, 'r') as z:
|
|
547
580
|
with z.open('record.pkl', 'r') as f:
|
|
548
581
|
description, items = dill.load(f)
|
|
582
|
+
with z.open('config.pkl', 'r') as f:
|
|
583
|
+
config = dill.load(f)
|
|
584
|
+
description['config'] = config
|
|
549
585
|
record = cls(None, None, description)
|
|
550
586
|
for key, value in items.items():
|
|
551
587
|
if isinstance(value, BufferList):
|
qulab/scan/scan.py
CHANGED
|
@@ -225,6 +225,7 @@ class Scan():
|
|
|
225
225
|
dump_globals: bool = False,
|
|
226
226
|
max_workers: int = 4,
|
|
227
227
|
max_promise: int = 100,
|
|
228
|
+
max_message: int = 1000,
|
|
228
229
|
mixin=None):
|
|
229
230
|
self.id = task_uuid()
|
|
230
231
|
self.record = None
|
|
@@ -265,11 +266,12 @@ class Scan():
|
|
|
265
266
|
self._sem = asyncio.Semaphore(max_promise + 1)
|
|
266
267
|
self._bar: dict[int, tqdm] = {}
|
|
267
268
|
self._hide_pattern_re = re.compile('|'.join(self.description['hiden']))
|
|
268
|
-
self._msg_queue = asyncio.Queue()
|
|
269
|
+
self._msg_queue = asyncio.Queue(max_message)
|
|
269
270
|
self._prm_queue = asyncio.Queue()
|
|
270
271
|
self._single_step = True
|
|
271
272
|
self._max_workers = max_workers
|
|
272
273
|
self._max_promise = max_promise
|
|
274
|
+
self._max_message = max_message
|
|
273
275
|
self._executors = ProcessPoolExecutor(max_workers=max_workers)
|
|
274
276
|
|
|
275
277
|
def __del__(self):
|
|
@@ -297,7 +299,7 @@ class Scan():
|
|
|
297
299
|
self._main_task = None
|
|
298
300
|
self._bar = {}
|
|
299
301
|
self._prm_queue = asyncio.Queue()
|
|
300
|
-
self._msg_queue = asyncio.Queue()
|
|
302
|
+
self._msg_queue = asyncio.Queue(self._max_message)
|
|
301
303
|
self._sem = asyncio.Semaphore(self._max_promise + 1)
|
|
302
304
|
self._executors = ProcessPoolExecutor(max_workers=self._max_workers)
|
|
303
305
|
for opt in self.description['optimizers'].values():
|
|
@@ -344,8 +346,9 @@ class Scan():
|
|
|
344
346
|
for k, v in variables.items() if not self.hiden(k)
|
|
345
347
|
})
|
|
346
348
|
|
|
347
|
-
def emit(self, current_level, step, position, variables: dict[str,
|
|
348
|
-
|
|
349
|
+
async def emit(self, current_level, step, position, variables: dict[str,
|
|
350
|
+
Any]):
|
|
351
|
+
await self._msg_queue.put(
|
|
349
352
|
self._emit(current_level, step, position, variables.copy()))
|
|
350
353
|
|
|
351
354
|
def hide(self, name: str):
|
|
@@ -552,16 +555,16 @@ class Scan():
|
|
|
552
555
|
if isinstance(
|
|
553
556
|
self.description['database'],
|
|
554
557
|
str) and self.description['database'].startswith("tcp://"):
|
|
555
|
-
async with ZMQContextManager(
|
|
556
|
-
|
|
557
|
-
|
|
558
|
+
async with ZMQContextManager(zmq.DEALER,
|
|
559
|
+
connect=self.description['database'],
|
|
560
|
+
socket=self._sock) as socket:
|
|
558
561
|
self._sock = socket
|
|
559
562
|
await self._run()
|
|
560
563
|
else:
|
|
561
564
|
await self._run()
|
|
562
565
|
|
|
563
566
|
async def _run(self):
|
|
564
|
-
|
|
567
|
+
send_msg_task = asyncio.create_task(self._send_msg())
|
|
565
568
|
update_progress_task = asyncio.create_task(self._update_progress())
|
|
566
569
|
|
|
567
570
|
self._variables = {'self': self}
|
|
@@ -596,13 +599,13 @@ class Scan():
|
|
|
596
599
|
self.description['order'].get(-1, []),
|
|
597
600
|
self.description['getters'], self.variables))
|
|
598
601
|
|
|
599
|
-
self.emit(0, 0, 0, self.variables)
|
|
600
|
-
self.emit(-1, 0, 0, {})
|
|
602
|
+
await self.emit(0, 0, 0, self.variables)
|
|
603
|
+
await self.emit(-1, 0, 0, {})
|
|
601
604
|
|
|
602
605
|
await self._prm_queue.join()
|
|
603
606
|
update_progress_task.cancel()
|
|
604
607
|
await self._msg_queue.join()
|
|
605
|
-
|
|
608
|
+
send_msg_task.cancel()
|
|
606
609
|
return self.variables
|
|
607
610
|
|
|
608
611
|
async def done(self):
|
|
@@ -621,13 +624,18 @@ class Scan():
|
|
|
621
624
|
|
|
622
625
|
async def submit(self, server=default_executor):
|
|
623
626
|
assymbly(self.description)
|
|
624
|
-
async with ZMQContextManager(zmq.DEALER,
|
|
627
|
+
async with ZMQContextManager(zmq.DEALER,
|
|
628
|
+
connect=server,
|
|
629
|
+
socket=self._sock) as socket:
|
|
625
630
|
await socket.send_pyobj({
|
|
626
|
-
'method': '
|
|
631
|
+
'method': 'task_submit',
|
|
627
632
|
'description': dill.dumps(self.description)
|
|
628
633
|
})
|
|
629
634
|
self.id = await socket.recv_pyobj()
|
|
630
|
-
await socket.send_pyobj({
|
|
635
|
+
await socket.send_pyobj({
|
|
636
|
+
'method': 'task_get_record_id',
|
|
637
|
+
'id': self.id
|
|
638
|
+
})
|
|
631
639
|
record_id = await socket.recv_pyobj()
|
|
632
640
|
self.record = Record(record_id, self.description['database'],
|
|
633
641
|
self.description)
|
|
@@ -661,14 +669,15 @@ class Scan():
|
|
|
661
669
|
if await self._filter(variables, self.current_level - 1):
|
|
662
670
|
yield variables
|
|
663
671
|
self._single_step = False
|
|
664
|
-
self.emit(self.current_level - 1, step, position,
|
|
672
|
+
await self.emit(self.current_level - 1, step, position,
|
|
673
|
+
variables)
|
|
665
674
|
step += 1
|
|
666
675
|
position += 1
|
|
667
676
|
self._current_level -= 1
|
|
668
677
|
self._prm_queue.put_nowait(
|
|
669
678
|
self._update_progress_bar(self.current_level, 1))
|
|
670
679
|
if self.current_level == 0:
|
|
671
|
-
self.emit(self.current_level - 1, 0, 0, {})
|
|
680
|
+
await self.emit(self.current_level - 1, 0, 0, {})
|
|
672
681
|
for name, value in self.variables.items():
|
|
673
682
|
if inspect.isawaitable(value):
|
|
674
683
|
self.variables[name] = await value
|
qulab/scan/server.py
CHANGED
|
@@ -2,6 +2,7 @@ import asyncio
|
|
|
2
2
|
import os
|
|
3
3
|
import pickle
|
|
4
4
|
import time
|
|
5
|
+
import uuid
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
import click
|
|
@@ -29,7 +30,9 @@ else:
|
|
|
29
30
|
datapath = Path.home() / 'qulab' / 'data'
|
|
30
31
|
datapath.mkdir(parents=True, exist_ok=True)
|
|
31
32
|
|
|
33
|
+
namespace = uuid.uuid4()
|
|
32
34
|
record_cache = {}
|
|
35
|
+
buffer_list_cache = {}
|
|
33
36
|
CACHE_SIZE = 1024
|
|
34
37
|
|
|
35
38
|
pool = {}
|
|
@@ -44,6 +47,9 @@ class Request():
|
|
|
44
47
|
self.msg = pickle.loads(msg)
|
|
45
48
|
self.method = self.msg.get('method', '')
|
|
46
49
|
|
|
50
|
+
def __repr__(self):
|
|
51
|
+
return f"Request({self.method})"
|
|
52
|
+
|
|
47
53
|
|
|
48
54
|
async def reply(req, resp):
|
|
49
55
|
await req.sock.send_multipart([req.identity, pickle.dumps(resp)])
|
|
@@ -57,6 +63,11 @@ def clear_cache():
|
|
|
57
63
|
range(len(record_cache) - CACHE_SIZE)):
|
|
58
64
|
del record_cache[k]
|
|
59
65
|
|
|
66
|
+
for k, (t,
|
|
67
|
+
_) in zip(sorted(buffer_list_cache.items(), key=lambda x: x[1][0]),
|
|
68
|
+
range(len(buffer_list_cache) - CACHE_SIZE)):
|
|
69
|
+
del buffer_list_cache[k]
|
|
70
|
+
|
|
60
71
|
|
|
61
72
|
def flush_cache():
|
|
62
73
|
for k, (t, r) in record_cache.items():
|
|
@@ -142,12 +153,37 @@ async def handle(session: Session, request: Request, datapath: Path):
|
|
|
142
153
|
match request.method:
|
|
143
154
|
case 'ping':
|
|
144
155
|
await reply(request, 'pong')
|
|
145
|
-
case '
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
156
|
+
case 'bufferlist_iter':
|
|
157
|
+
if msg['iter_id'] in buffer_list_cache:
|
|
158
|
+
it = buffer_list_cache[msg['iter_id']][1]
|
|
159
|
+
iter_id = msg['iter_id']
|
|
160
|
+
else:
|
|
161
|
+
iter_id = uuid.uuid3(namespace, str(time.time_ns())).bytes
|
|
162
|
+
record = get_record(session, msg['record_id'], datapath)
|
|
163
|
+
bufferlist = record.get(msg['key'],
|
|
164
|
+
buffer_to_array=False,
|
|
165
|
+
slice=msg['slice'])
|
|
166
|
+
it = bufferlist.iter()
|
|
167
|
+
for _, _ in zip(range(msg['start']), it):
|
|
168
|
+
pass
|
|
169
|
+
current_time = time.time()
|
|
170
|
+
ret, end = [], False
|
|
171
|
+
while time.time() - current_time < 0.02:
|
|
172
|
+
try:
|
|
173
|
+
ret.append(next(it))
|
|
174
|
+
except StopIteration:
|
|
175
|
+
end = True
|
|
176
|
+
break
|
|
177
|
+
await reply(request, (iter_id, ret, end))
|
|
178
|
+
buffer_list_cache[iter_id] = time.time(), it
|
|
179
|
+
clear_cache()
|
|
180
|
+
case 'bufferlist_iter_exit':
|
|
181
|
+
try:
|
|
182
|
+
it = buffer_list_cache.pop(msg['iter_id'])[1]
|
|
183
|
+
it.throw(Exception)
|
|
184
|
+
except:
|
|
185
|
+
pass
|
|
186
|
+
clear_cache()
|
|
151
187
|
case 'record_create':
|
|
152
188
|
description = dill.loads(msg['description'])
|
|
153
189
|
await reply(request, record_create(session, description, datapath))
|
|
@@ -220,7 +256,7 @@ async def handle(session: Session, request: Request, datapath: Path):
|
|
|
220
256
|
'objects').parts[-4:]))
|
|
221
257
|
session.commit()
|
|
222
258
|
await reply(request, config.id)
|
|
223
|
-
case '
|
|
259
|
+
case 'task_submit':
|
|
224
260
|
from .scan import Scan
|
|
225
261
|
finished = [(id, queried) for id, (task, queried) in pool.items()
|
|
226
262
|
if not isinstance(task, int) and task.finished()]
|
|
@@ -235,7 +271,7 @@ async def handle(session: Session, request: Request, datapath: Path):
|
|
|
235
271
|
task.start()
|
|
236
272
|
pool[task.id] = [task, False]
|
|
237
273
|
await reply(request, task.id)
|
|
238
|
-
case '
|
|
274
|
+
case 'task_get_record_id':
|
|
239
275
|
task, queried = pool.get(msg['id'])
|
|
240
276
|
if isinstance(task, int):
|
|
241
277
|
await reply(request, task)
|
|
@@ -249,15 +285,28 @@ async def handle(session: Session, request: Request, datapath: Path):
|
|
|
249
285
|
await asyncio.sleep(1)
|
|
250
286
|
else:
|
|
251
287
|
await reply(request, None)
|
|
288
|
+
case 'task_get_progress':
|
|
289
|
+
task, _ = pool.get(msg['id'])
|
|
290
|
+
if isinstance(task, int):
|
|
291
|
+
await reply(request, 1)
|
|
292
|
+
else:
|
|
293
|
+
await reply(request,
|
|
294
|
+
[(bar.n, bar.total) for bar in task._bar.values()])
|
|
252
295
|
case _:
|
|
253
296
|
logger.error(f"Unknown method: {msg['method']}")
|
|
254
297
|
|
|
255
298
|
|
|
256
|
-
async def
|
|
299
|
+
async def handle_with_timeout(session: Session, request: Request,
|
|
300
|
+
datapath: Path, timeout: float):
|
|
257
301
|
try:
|
|
258
|
-
await handle(session, request, datapath)
|
|
259
|
-
|
|
260
|
-
|
|
302
|
+
await asyncio.wait_for(handle(session, request, datapath),
|
|
303
|
+
timeout=timeout)
|
|
304
|
+
except asyncio.TimeoutError:
|
|
305
|
+
logger.warning(
|
|
306
|
+
f"Task handling request {request} timed out and was cancelled.")
|
|
307
|
+
await reply(request, 'timeout')
|
|
308
|
+
except Exception as e:
|
|
309
|
+
await reply(request, f'{e!r}')
|
|
261
310
|
|
|
262
311
|
|
|
263
312
|
async def serv(port,
|
|
@@ -280,7 +329,8 @@ async def serv(port,
|
|
|
280
329
|
identity, msg = await sock.recv_multipart()
|
|
281
330
|
received += len(msg)
|
|
282
331
|
req = Request(sock, identity, msg)
|
|
283
|
-
asyncio.create_task(
|
|
332
|
+
asyncio.create_task(
|
|
333
|
+
handle_with_timeout(session, req, datapath, timeout=60.0))
|
|
284
334
|
if received > buffer_size or time.time(
|
|
285
335
|
) - last_flush_time > interval:
|
|
286
336
|
flush_cache()
|
qulab/scan/space.py
CHANGED
|
@@ -28,6 +28,8 @@ class Space():
|
|
|
28
28
|
return space
|
|
29
29
|
if isinstance(space, (list, tuple)):
|
|
30
30
|
array = np.array(space)
|
|
31
|
+
elif isinstance(space, np.ndarray):
|
|
32
|
+
array = space
|
|
31
33
|
try:
|
|
32
34
|
a = np.linspace(array[0], array[-1], len(array), dtype=array.dtype)
|
|
33
35
|
if np.allclose(a, array):
|
qulab/sys/rpc/zmq_socket.py
CHANGED
|
@@ -130,7 +130,12 @@ class ZMQContextManager:
|
|
|
130
130
|
self.auth = None
|
|
131
131
|
self.context = None
|
|
132
132
|
self.socket = None
|
|
133
|
-
self._external_socket =
|
|
133
|
+
self._external_socket = None
|
|
134
|
+
try:
|
|
135
|
+
if not socket.closed:
|
|
136
|
+
self._external_socket = socket
|
|
137
|
+
except:
|
|
138
|
+
pass
|
|
134
139
|
|
|
135
140
|
def _create_socket(self, asyncio=False) -> zmq.Socket:
|
|
136
141
|
"""
|
qulab/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "2.2.
|
|
1
|
+
__version__ = "2.2.6"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|