У меня есть некоторый Python код с расширенными аннотациями типов, классы, которые по сути являются прославленными структурами (свойство ниже - единственный метод в моих классах) и необходимость его быстрого выполнения.
@dataclass
class Family:
"""A family group agent."""
descendence: str
culture: int
location_history: List[h3.c_int] = field(default_factory=list)
@property
def location(self) -> h3.c_int:
return self.location_history[0]
number_offspring: int = 0
effective_size: int = 2
stored_resources: float = 130000.0
seasons_till_next_child: int = 4
seasons_till_next_mutation: Optional[int] = None
@dataclass
class Patch:
"""A patch of land with resources."""
resources: float
max_resources: float
Например, у меня есть agents: List[Tuple[Patch, Sequence[Family]]]
(это немного сложнее, но это не имеет значения для вопроса о принципе) и эти две функции
def extract_resources(
patch: Patch, group: Sequence[Family], total_labor_here: int) -> kcal:
"""Distribute the resources gained from cooperative extraction."""
labor = sum([family.effective_size
for family in group])
resources_extracted = resources_from_patch(
patch, labor, total_labor_here - labor)
for family in group:
family.stored_resources += (
resources_extracted * family.effective_size / labor)
return resources_extracted
и
def resources_from_patch(
patch: Patch,
labor: int,
others_labor: int,
estimate: bool = False) -> float:
"""Compute or estimate the resources a cooperative gains from a patch."""
my_relative_returns = (
time_step_energy_use * labor *
effective_labor_through_cooperation(labor))
if not estimate:
my_relative_returns = numpy.maximum(
random.gauss(
mu=my_relative_returns,
sigma=(params.payoff_standarddeviation *
time_step_energy_use / labor ** 0.5)),
0)
if others_labor:
others_relative_returns = (
time_step_energy_use * others_labor *
effective_labor_through_cooperation(others_labor))
if not estimate:
others_relative_returns = numpy.maximum(
random.gauss(
mu=others_relative_returns,
sigma=(params.payoff_standarddeviation *
time_step_energy_use / others_labor ** 0.5)),
0)
else:
others_relative_returns = 0
return (my_relative_returns) / (
my_relative_returns + others_relative_returns) * min(
my_relative_returns + others_relative_returns,
patch.resources * params.accessible_resources)
и я хочу выполнить
for patch, families in agents:
extract_resources(patch, families, sum(family.effective_size for family in families))
как можно быстрее (включая параллельное выполнение extract_resources
для каждого патча, они гарантированно не будут взаимодействовать).
Я бы хотел сохраните это как что-то, что может быть интерпретировано python, проверено mypy
и python линтерами. Я предполагаю, что чистый python режим Cython мог бы помочь мне достичь этого, но я не понимаю, как изменить этот исходный код, чтобы он выполнялся максимально быстрым способом в Cython при этих ограничениях. Я посмотрел на numba
, но я не нашел способа заставить его соблюдать мои структурированные классы, аннотированные типом.
Какие аннотации типов, декораторы и незначительные рефакторинги я должен использовать для выполнить этот стиль кода Python самым быстрым параллельным способом без ограничения GIL?