使用多个 threads/cores 提高性能
Improving preformance by using multiple threads/cores
我有一个游戏(使用 pygame),我想提高它的性能。我注意到当我的 fps 很低时,游戏最多只使用 20% 的 CPU,有没有一种方法可以让我使用线程来利用更多的 CPU?
我已经尝试实现线程,但似乎运气不佳,希望能提供一些帮助。
这个函数是导致延迟的原因:
第一个版本
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 个元素(或更多)长,因此需要很长时间来遍历和排序。然后为了补救,我想通过线程使用更多的 CPU 。
如果对您有帮助,请查看完整脚本:https://github.com/Lobsternator/Game-Of-Life-Esque.git
在Python中,线程不会增加使用的核心数。您必须改用多处理。
文档:https://docs.python.org/3.7/library/multiprocessing.html#multiprocessing.Manager
Python 中的多线程几乎毫无用处(对于 CPU 这样的密集型任务),多处理虽然可行,但需要在进程之间进行昂贵的数据编组或精心设计。我认为两者都不适用于您的情况。
但是,除非您的游戏中有大量对象,否则您不需要为场景使用多核。这个问题似乎更多的是算法复杂性。
您可以通过多种方式提高代码的性能:
- 按类型保留实体索引(例如,从实体类型到实体集的字典,您将其更新为实体 created/removed),这样您就可以轻松找到所有 "food" 实体而不扫描游戏中的所有实体。
- 使用简单的 "min" 操作(即
O(n)
)找到最近的食物实体,而不是按距离对所有食物进行排序(即 O(n*logn)
)。
- 如果这仍然很慢,您可以应用剔除技术,首先将食物过滤到易于计算范围内的食物(例如玩家周围的矩形),然后通过应用更昂贵的距离找到最近的食物只计算那些。
- 通过避免检查循环中不必要的条件并尽可能使用内置 selection/creation 构造而不是遍历大型对象列表来使循环更紧密。
例如你可以得到类似的结果:
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
用于常规距离计算。这对于其他向量算术运算也可能有用。
我有一个游戏(使用 pygame),我想提高它的性能。我注意到当我的 fps 很低时,游戏最多只使用 20% 的 CPU,有没有一种方法可以让我使用线程来利用更多的 CPU?
我已经尝试实现线程,但似乎运气不佳,希望能提供一些帮助。
这个函数是导致延迟的原因:
第一个版本
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 个元素(或更多)长,因此需要很长时间来遍历和排序。然后为了补救,我想通过线程使用更多的 CPU 。
如果对您有帮助,请查看完整脚本:https://github.com/Lobsternator/Game-Of-Life-Esque.git
在Python中,线程不会增加使用的核心数。您必须改用多处理。
文档:https://docs.python.org/3.7/library/multiprocessing.html#multiprocessing.Manager
Python 中的多线程几乎毫无用处(对于 CPU 这样的密集型任务),多处理虽然可行,但需要在进程之间进行昂贵的数据编组或精心设计。我认为两者都不适用于您的情况。
但是,除非您的游戏中有大量对象,否则您不需要为场景使用多核。这个问题似乎更多的是算法复杂性。
您可以通过多种方式提高代码的性能:
- 按类型保留实体索引(例如,从实体类型到实体集的字典,您将其更新为实体 created/removed),这样您就可以轻松找到所有 "food" 实体而不扫描游戏中的所有实体。
- 使用简单的 "min" 操作(即
O(n)
)找到最近的食物实体,而不是按距离对所有食物进行排序(即O(n*logn)
)。- 如果这仍然很慢,您可以应用剔除技术,首先将食物过滤到易于计算范围内的食物(例如玩家周围的矩形),然后通过应用更昂贵的距离找到最近的食物只计算那些。
- 通过避免检查循环中不必要的条件并尽可能使用内置 selection/creation 构造而不是遍历大型对象列表来使循环更紧密。
例如你可以得到类似的结果:
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
用于常规距离计算。这对于其他向量算术运算也可能有用。