У меня есть игра (использующая pygame), производительность которой я хочу улучшить. Я заметил, что когда у меня низкий fps, игра использует максимум 20% ЦП, есть ли способ использовать потоки, чтобы использовать больше ЦП?
Я уже пытался реализовать потоки, но, похоже, мне не повезло, некоторая помощь будет оценена по достоинству.
Эта функция вызывает отставание:
def SearchFood(self):
if not self.moving:
tempArr = np.array([])
for e in entityArr:
if type(e) == Food:
if e.rect != None and self.viewingRect != None:
if self.viewingRect.colliderect(e.rect):
tempArr = np.append(tempArr, e)
if tempArr.size > 0:
self.nearestFood = sorted(tempArr, key=lambda e: Mag((self.x - e.x, self.y - e.y)))[0]
def SearchFood(self):
if not self.moving:
s_arr = sorted(entityArr, key=lambda e: math.hypot(self.x - e.x, self.y - e.y))
for e, i in enumerate(s_arr):
if type(e) != Food:
self.nearestFood = None
else:
self.nearestFood = s_arr[i]
break
Я просматриваю весь список сущностей и сортирую его по тому, является ли сущность едой и расстоянием до существа, которое хочет съесть указанную еду. Проблема в том, что массив сущностей состоит из 500 элементов (и более), и поэтому для его итерации и сортировки требуется очень много времени. Затем, чтобы исправить это, я хочу использовать больше ЦП с использованием потоковой передачи.
Вот полный скрипт, если поможет: https://github.com/Lobsternator/Game-Of-Life-Esque.git
В Python многопоточность не увеличивает количество используемых ядер. Вместо этого вы должны использовать многопроцессорность. Документ: https://docs.python.org/3.7/library/multiprocessing.html#multiprocessing.Manager
Многопоточность в Python почти бесполезна (для таких ресурсоемких задач, как эта), а многопроцессорность, хотя и жизнеспособна, требует дорогостоящей маршалинга данных между процессами или тщательного проектирования. Я не верю, что любой из них применим к вашему случаю.
Однако, если в вашей игре нет огромного количества объектов, вам не нужно использовать несколько ядер для вашего сценария. Проблема кажется скорее одной из алгоритмической сложности.
Вы можете улучшить производительность вашего кода несколькими способами:
O(n)
) вместо сортировки всех продуктов по расстоянию (это O(n*logn)
).
например вы можете получить что-то вроде:
def find_nearest_food(self):
food_entities = self._entities_by_type[Food]
nearest_food = min(food_entities, key=lambda entity: distance_sq(self, entity))
return nearest_food
def distance_sq(ent1, ent2):
# we don't need an expensive square root operation if we're just comparing distances
dx, dy = (ent1.x - ent2.x), (ent1.y - ent2.y)
return dx * dx + dy * dy
Вы можете оптимизировать дальнейшую оптимизацию, сохраняя позиции объектов в виде векторов NumPy вместо отдельных свойств x
и y
, что позволит вам использовать операции NumPy для расчета расстояния, например. distance_sq = (ent1.pos - ent2.pos)**2
или просто np.linalg.norm
для обычного вычисления расстояния. Это также может быть полезно для других векторных арифметических операций.
Вы сможете увеличить вычислительную мощность только в том случае, если у вас есть все доступные объекты для многопроцессорность, готовые и поставленные в очередь, поэтому, если вы генерируете по одному или нуждаетесь в нем для заказа, это будет сложнее. Также имейте в виду, что Python действительно плохо справляется с этой параллельной работой, и этот «официальный» хак должен быть реализован осторожно, как показано (особенно для Windows), иначе он приведет к зависанию либо приложения, либо всей вашей машины. Вместо этого можно попробовать оптимизировать.