Skip to content

Commit

Permalink
PERF: drop GIL during long-running proj database calls (#1354)
Browse files Browse the repository at this point in the history
These calls can take hundreds of milliseconds to access the PROJ
databases, during which time no other Python code in any other thread
can run. Use `nogil` to avoid this effect.

This should be safe for these calls as they all take a separate PROJ
threading context.
  • Loading branch information
tpwrules committed Oct 26, 2023
1 parent 3cea713 commit 16c04e2
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 27 deletions.
17 changes: 9 additions & 8 deletions pyproj/_transformer.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -330,14 +330,15 @@ cdef PJ* proj_create_crs_to_crs(
ELSE:
raise NotImplementedError("only_best requires PROJ 9.2+.")


cdef PJ* transform = proj_create_crs_to_crs_from_pj(
ctx,
source_crs,
target_crs,
area,
options,
)
cdef PJ* transform = NULL
with nogil:
transform = proj_create_crs_to_crs_from_pj(
ctx,
source_crs,
target_crs,
area,
options,
)
proj_destroy(source_crs)
proj_destroy(target_crs)
if transform == NULL:
Expand Down
48 changes: 29 additions & 19 deletions pyproj/database.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ def get_authorities():
Authorities in PROJ database.
"""
cdef PJ_CONTEXT* context = pyproj_context_create()
cdef PROJ_STRING_LIST proj_auth_list = proj_get_authorities_from_database(context)
cdef PROJ_STRING_LIST proj_auth_list = NULL
with nogil:
proj_auth_list = proj_get_authorities_from_database(context)
if proj_auth_list == NULL:
pyproj_context_destroy(context)
return []
Expand Down Expand Up @@ -108,14 +110,19 @@ def get_codes(str auth_name not None, pj_type not None, bint allow_deprecated=Fa
cdef PJ_CONTEXT* context = NULL
cdef PJ_TYPE cpj_type = get_pj_type(pj_type)
cdef PROJ_STRING_LIST proj_code_list = NULL
cdef const char* c_auth_name = NULL
cdef bytes b_auth_name
try:
context = pyproj_context_create()
proj_code_list = proj_get_codes_from_database(
context,
cstrencode(auth_name),
cpj_type,
allow_deprecated,
)
b_auth_name = cstrencode(auth_name)
c_auth_name = b_auth_name
with nogil:
proj_code_list = proj_get_codes_from_database(
context,
c_auth_name,
cpj_type,
allow_deprecated,
)
finally:
pyproj_context_destroy(context)
if proj_code_list == NULL:
Expand Down Expand Up @@ -239,11 +246,12 @@ def query_crs_info(
query_params.east_lon_degree = area_of_interest.east_lon_degree
query_params.north_lat_degree = area_of_interest.north_lat_degree

crs_info_list = proj_get_crs_info_list_from_database(
context,
c_auth_name,
query_params,
&result_count)
with nogil:
crs_info_list = proj_get_crs_info_list_from_database(
context,
c_auth_name,
query_params,
&result_count)
finally:
if query_params != NULL:
proj_get_crs_list_parameters_destroy(query_params)
Expand Down Expand Up @@ -400,13 +408,15 @@ def get_units_map(str auth_name=None, str category=None, bint allow_deprecated=F

cdef int num_units = 0
cdef PJ_CONTEXT* context = pyproj_context_create()
cdef PROJ_UNIT_INFO** db_unit_list = proj_get_units_from_database(
context,
c_auth_name,
c_category,
bool(allow_deprecated),
&num_units,
)
cdef PROJ_UNIT_INFO** db_unit_list = NULL
with nogil:
db_unit_list = proj_get_units_from_database(
context,
c_auth_name,
c_category,
bool(allow_deprecated),
&num_units,
)
units_map = {}
try:
for iii in range(num_units):
Expand Down

0 comments on commit 16c04e2

Please sign in to comment.