-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmultiproc_data.py
More file actions
144 lines (130 loc) · 4.26 KB
/
Copy pathmultiproc_data.py
File metadata and controls
144 lines (130 loc) · 4.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from __future__ import print_function
from ctypes import c_bool
import multiprocessing as mp
try:
from queue import Full as QFullExcept
from queue import Empty as QEmptyExcept
except ImportError:
from Queue import Full as QFullExcept
from Queue import Empty as QEmptyExcept
import numpy as np
class MPData(object):
"""
Handles multi-process data generation.
Operation:
- call start() to start the data generation
- call get() (blocking) to read one sample
- call reset() to stop data generation
"""
def __init__(self, num_processes, max_queue_size, fn):
"""
Parameters
----------
num_processes: int
Number of processes to spawn
max_queue_size: int
Maximum samples in the queue before processes wait
fn: function
function that generates samples, executed on separate processes.
"""
self.queue = mp.Queue(maxsize=int(max_queue_size))
self.alive = mp.Value(c_bool, False, lock=False)
self.num_proc = num_processes
self.proc = list()
self.fn = fn
def start(self):
"""
Starts the processes
Parameters
----------
fn: function
"""
"""
Starts the processes
"""
self._init_proc()
@staticmethod
def _proc_loop(proc_id, alive, queue, fn):
"""
Thread loop for generating data
Parameters
----------
proc_id: int
Process id
alive: multiprocessing.Value
variable for signaling whether process should continue or not
queue: multiprocessing.Queue
queue for passing data back
fn: function
function object that returns a sample to be pushed into the queue
"""
print("proc {} started".format(proc_id))
try:
while alive.value:
data = fn()
put_success = False
while alive.value and not put_success:
try:
queue.put(data, timeout=0.5)
put_success = True
except QFullExcept:
# print("Queue Full")
pass
except KeyboardInterrupt:
print("W: interrupt received, stopping process {} ...".format(proc_id))
print("Closing process {}".format(proc_id))
queue.close()
def _init_proc(self):
"""
Start processes if not already started
"""
if not self.proc:
self.proc = [
mp.Process(target=self._proc_loop, args=(i, self.alive, self.queue, self.fn))
for i in range(self.num_proc)
]
self.alive.value = True
for p in self.proc:
p.start()
def get(self):
"""
Get a datum from the queue
Returns
-------
np.ndarray
A captcha image, normalized to [0, 1]
"""
self._init_proc()
return self.queue.get()
def reset(self):
"""
Resets the generator by stopping all processes
"""
self.alive.value = False
qsize = 0
try:
while True:
self.queue.get(timeout=0.1)
qsize += 1
except QEmptyExcept:
pass
print("Queue size on reset: {}".format(qsize))
for i, p in enumerate(self.proc):
p.join()
self.proc.clear()