test_gil.py 1.8 KB

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