test_gil.py 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import itertools
  2. import threading
  3. import time
  4. import numpy as np
  5. from numpy.testing import assert_equal
  6. import pytest
  7. import scipy.interpolate
  8. class TestGIL:
  9. """Check if the GIL is properly released by scipy.interpolate functions."""
  10. def setup_method(self):
  11. self.messages = []
  12. def log(self, message):
  13. self.messages.append(message)
  14. def make_worker_thread(self, target, args):
  15. log = self.log
  16. class WorkerThread(threading.Thread):
  17. def run(self):
  18. log('interpolation started')
  19. target(*args)
  20. log('interpolation complete')
  21. return WorkerThread()
  22. @pytest.mark.slow
  23. @pytest.mark.xfail(reason='race conditions, may depend on system load')
  24. def test_rectbivariatespline(self):
  25. def generate_params(n_points):
  26. x = y = np.linspace(0, 1000, n_points)
  27. x_grid, y_grid = np.meshgrid(x, y)
  28. z = x_grid * y_grid
  29. return x, y, z
  30. def calibrate_delay(requested_time):
  31. for n_points in itertools.count(5000, 1000):
  32. args = generate_params(n_points)
  33. time_started = time.time()
  34. interpolate(*args)
  35. if time.time() - time_started > requested_time:
  36. return args
  37. def interpolate(x, y, z):
  38. scipy.interpolate.RectBivariateSpline(x, y, z)
  39. args = calibrate_delay(requested_time=3)
  40. worker_thread = self.make_worker_thread(interpolate, args)
  41. worker_thread.start()
  42. for i in range(3):
  43. time.sleep(0.5)
  44. self.log('working')
  45. worker_thread.join()
  46. assert_equal(self.messages, [
  47. 'interpolation started',
  48. 'working',
  49. 'working',
  50. 'working',
  51. 'interpolation complete',
  52. ])