@@ -64,6 +64,25 @@ def get_batch(env_ids, dim, t, x):
6464 reward = r )
6565
6666
67+ def _enqueue_after_delay (ring_buffer , batch , delay = 0.04 ):
68+ alf .set_default_device ("cpu" )
69+ sleep (delay )
70+ ring_buffer .enqueue (batch , batch .env_id )
71+
72+
73+ def _dequeue_after_delay (ring_buffer ):
74+ # cpu tensor on subprocess. Otherwise, spawn method is needed.
75+ alf .set_default_device ("cpu" )
76+ sleep (0.04 )
77+ ring_buffer .dequeue () # 6(deleted), 7, 8, 9
78+ sleep (0.04 ) # 10, 7, 8, 9
79+ ring_buffer .dequeue () # 10, 7(deleted), 8, 9
80+
81+
82+ def _blocking_dequeue (ring_buffer ):
83+ ring_buffer .dequeue (blocking = True )
84+
85+
6786class RingBufferTest (parameterized .TestCase , alf .test .TestCase ):
6887 dim = 20
6988 max_length = 4
@@ -86,15 +105,16 @@ def __init__(self, *args):
86105 ('test_sync' , False ),
87106 ('test_async' , True ),
88107 ])
89- def test_ring_buffer (self , allow_multiprocess ):
108+ def test_ring_buffer (self , use_mp_context ):
109+ mp_ctx = mp .get_context ('spawn' ) if use_mp_context else None
90110 ring_buffer = RingBuffer (data_spec = self .data_spec ,
91111 num_environments = self .num_envs ,
92112 max_length = self .max_length ,
93- allow_multiprocess = allow_multiprocess )
113+ mp_context = mp_ctx )
94114
95115 batch1 = get_batch ([1 , 2 , 3 , 5 , 6 ], self .dim , t = 1 , x = 0.4 )
96- if not allow_multiprocess :
97- # enqueue: blocking mode only available under allow_multiprocess
116+ if not use_mp_context :
117+ # enqueue: blocking mode only available when multiprocessing is enabled
98118 self .assertRaises (AssertionError ,
99119 ring_buffer .enqueue ,
100120 batch1 ,
@@ -107,8 +127,8 @@ def test_ring_buffer(self, allow_multiprocess):
107127 # test that the created batch has gradients
108128 self .assertTrue (batch1 .x .requires_grad )
109129 ring_buffer .enqueue (batch1 , batch1 .env_id )
110- if not allow_multiprocess :
111- # dequeue: blocking mode only available under allow_multiprocess
130+ if not use_mp_context :
131+ # dequeue: blocking mode only available when multiprocessing is enabled
112132 self .assertRaises (AssertionError ,
113133 ring_buffer .dequeue ,
114134 env_ids = batch1 .env_id ,
@@ -159,17 +179,13 @@ def test_ring_buffer(self, allow_multiprocess):
159179 ring_buffer .remove_up_to (3 )
160180 self .assertEqual (ring_buffer ._current_size , torch .tensor ([0 ] * 8 ))
161181
162- if allow_multiprocess :
182+ if use_mp_context :
163183 # Test block on dequeue without enough data
164- def delayed_enqueue (ring_buffer , batch ):
165- alf .set_default_device ("cpu" )
166- sleep (0.04 )
167- ring_buffer .enqueue (batch , batch .env_id )
168-
169- p = mp .Process (target = delayed_enqueue ,
170- args = (ring_buffer ,
171- alf .nest .map_structure (
172- lambda x : x .cpu (), batch1 )))
184+ batch1_cpu = alf .nest .map_structure (
185+ lambda tensor : tensor .detach ().cpu ()
186+ if isinstance (tensor , torch .Tensor ) else tensor , batch1 )
187+ p = mp_ctx .Process (target = _enqueue_after_delay ,
188+ args = (ring_buffer , batch1_cpu ))
173189 p .start ()
174190 batch = ring_buffer .dequeue (env_ids = batch1 .env_id , blocking = True )
175191 self .assertEqual (batch .step_type , torch .tensor ([[9 ]] * 5 ))
@@ -180,26 +196,16 @@ def delayed_enqueue(ring_buffer, batch):
180196 batch2 = get_batch (range (0 , 8 ), self .dim , t = t , x = 0.4 )
181197 ring_buffer .enqueue (batch2 )
182198
183- def delayed_dequeue ():
184- # cpu tensor on subprocess. Otherwise, spawn method is needed.
185- alf .set_default_device ("cpu" )
186- sleep (0.04 )
187- ring_buffer .dequeue () # 6(deleted), 7, 8, 9
188- sleep (0.04 ) # 10, 7, 8, 9
189- ring_buffer .dequeue () # 10, 7(deleted), 8, 9
190-
191- p = mp .Process (target = delayed_dequeue )
199+ p = mp_ctx .Process (target = _dequeue_after_delay ,
200+ args = (ring_buffer , ))
192201 p .start ()
193202 batch2 = get_batch (range (0 , 8 ), self .dim , t = 10 , x = 0.4 )
194203 ring_buffer .enqueue (batch2 , blocking = True )
195204 p .join ()
196205 self .assertEqual (ring_buffer ._current_size [0 ], torch .tensor (3 ))
197206
198207 # Test stop queue event
199- def blocking_dequeue (ring_buffer ):
200- ring_buffer .dequeue (blocking = True )
201-
202- p = mp .Process (target = blocking_dequeue , args = (ring_buffer , ))
208+ p = mp_ctx .Process (target = _blocking_dequeue , args = (ring_buffer , ))
203209 ring_buffer .clear ()
204210 p .start ()
205211 sleep (0.02 ) # for subprocess to enter while loop
0 commit comments