- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
问题:
我已经对我的 Python 程序进行了分析,并且有一个函数会减慢一切。它大量使用 Python 字典,所以我可能没有以最好的方式使用它们。如果我不能让它运行得更快,我将不得不用 C++ 重新编写它,那么有没有人可以帮助我用 Python 优化它?
我希望我已经给出了正确的解释,并且你可以理解我的代码!在此先感谢您的帮助。
我的代码:
这是有问题的函数,使用 line_profiler and kernprof 进行分析。我正在运行 Python 2.7
我对诸如第 363、389 和 405 行之类的事情感到特别困惑,其中比较两个变量的 if
语句似乎花费了过多的时间。
我已经考虑过使用 NumPy(因为它使用稀疏矩阵),但我认为它不合适,因为:(1)我没有使用整数索引我的矩阵(我使用的是对象实例); (2) 我没有在矩阵中存储简单的数据类型(我存储的是浮点数和对象实例的元组)。
但我愿意被 NumPy 说服。
如果有人知道 NumPy 的稀疏矩阵性能与 Python 的哈希表,我会很感兴趣。
抱歉,我没有给出一个您可以运行的简单示例,但此功能被捆绑在一个更大的项目中,我无法弄清楚如何设置一个简单的示例来测试它,而不给您一半的代码根据!
Timer unit: 3.33366e-10 s
File: routing_distances.py
Function: propagate_distances_node at line 328
Total time: 807.234 s
Line # Hits Time Per Hit % Time Line Contents
328 @profile
329 def propagate_distances_node(self, node_a, cutoff_distance=200):
330
331 # a makes sure its immediate neighbours are correctly in its distance table
332 # because its immediate neighbours may change as binds/folding change
333 737753 3733642341 5060.8 0.2 for (node_b, neighbour_distance_b_a) in self.neighbours[node_a].iteritems():
334 512120 2077788924 4057.2 0.1 use_neighbour_link = False
335
336 512120 2465798454 4814.9 0.1 if(node_b not in self.node_distances[node_a]): # a doesn't know distance to b
337 15857 66075687 4167.0 0.0 use_neighbour_link = True
338 else: # a does know distance to b
339 496263 2390534838 4817.1 0.1 (node_distance_b_a, next_node) = self.node_distances[node_a][node_b]
340 496263 2058112872 4147.2 0.1 if(node_distance_b_a > neighbour_distance_b_a): # neighbour distance is shorter
341 81 331794 4096.2 0.0 use_neighbour_link = True
342 496182 2665644192 5372.3 0.1 elif((None == next_node) and (float('+inf') == neighbour_distance_b_a)): # direct route that has just broken
343 75 313623 4181.6 0.0 use_neighbour_link = True
344
345 512120 1992514932 3890.7 0.1 if(use_neighbour_link):
346 16013 78149007 4880.3 0.0 self.node_distances[node_a][node_b] = (neighbour_distance_b_a, None)
347 16013 83489949 5213.9 0.0 self.nodes_changed.add(node_a)
348
349 ## Affinity distances update
350 16013 86020794 5371.9 0.0 if((node_a.type == Atom.BINDING_SITE) and (node_b.type == Atom.BINDING_SITE)):
351 164 3950487 24088.3 0.0 self.add_affinityDistance(node_a, node_b, self.chemistry.affinity(node_a.data, node_b.data))
352
353 # a sends its table to all its immediate neighbours
354 737753 3549685140 4811.5 0.1 for (node_b, neighbour_distance_b_a) in self.neighbours[node_a].iteritems():
355 512120 2129343210 4157.9 0.1 node_b_changed = False
356
357 # b integrates a's distance table with its own
358 512120 2203821081 4303.3 0.1 node_b_chemical = node_b.chemical
359 512120 2409257898 4704.5 0.1 node_b_distances = node_b_chemical.node_distances[node_b]
360
361 # For all b's routes (to c) that go to a first, update their distances
362 41756882 183992040153 4406.3 7.6 for node_c, (distance_b_c, node_after_b) in node_b_distances.iteritems(): # Think it's ok to modify items while iterating over them (just not insert/delete) (seems to work ok)
363 41244762 172425596985 4180.5 7.1 if(node_after_b == node_a):
364
365 16673654 64255631616 3853.7 2.7 try:
366 16673654 88781802534 5324.7 3.7 distance_b_a_c = neighbour_distance_b_a + self.node_distances[node_a][node_c][0]
367 187083 929898684 4970.5 0.0 except KeyError:
368 187083 1056787479 5648.8 0.0 distance_b_a_c = float('+inf')
369
370 16673654 69374705256 4160.7 2.9 if(distance_b_c != distance_b_a_c): # a's distance to c has changed
371 710083 3136751361 4417.4 0.1 node_b_distances[node_c] = (distance_b_a_c, node_a)
372 710083 2848845276 4012.0 0.1 node_b_changed = True
373
374 ## Affinity distances update
375 710083 3484577241 4907.3 0.1 if((node_b.type == Atom.BINDING_SITE) and (node_c.type == Atom.BINDING_SITE)):
376 99592 1591029009 15975.5 0.1 node_b_chemical.add_affinityDistance(node_b, node_c, self.chemistry.affinity(node_b.data, node_c.data))
377
378 # If distance got longer, then ask b's neighbours to update
379 ## TODO: document this!
380 16673654 70998570837 4258.1 2.9 if(distance_b_a_c > distance_b_c):
381 #for (node, neighbour_distance) in node_b_chemical.neighbours[node_b].iteritems():
382 1702852 7413182064 4353.4 0.3 for node in node_b_chemical.neighbours[node_b]:
383 1204903 5912053272 4906.7 0.2 node.chemical.nodes_changed.add(node)
384
385 # Look for routes from a to c that are quicker than ones b knows already
386 42076729 184216680432 4378.1 7.6 for node_c, (distance_a_c, node_after_a) in self.node_distances[node_a].iteritems():
387
388 41564609 171150289218 4117.7 7.1 node_b_update = False
389 41564609 172040284089 4139.1 7.1 if(node_c == node_b): # a-b path
390 512120 2040112548 3983.7 0.1 pass
391 41052489 169406668962 4126.6 7.0 elif(node_after_a == node_b): # a-b-a-b path
392 16251407 63918804600 3933.1 2.6 pass
393 24801082 101577038778 4095.7 4.2 elif(node_c in node_b_distances): # b can already get to c
394 24004846 103404357180 4307.6 4.3 (distance_b_c, node_after_b) = node_b_distances[node_c]
395 24004846 102717271836 4279.0 4.2 if(node_after_b != node_a): # b doesn't already go to a first
396 7518275 31858204500 4237.4 1.3 distance_b_a_c = neighbour_distance_b_a + distance_a_c
397 7518275 33470022717 4451.8 1.4 if(distance_b_a_c < distance_b_c): # quicker to go via a
398 225357 956440656 4244.1 0.0 node_b_update = True
399 else: # b can't already get to c
400 796236 3415455549 4289.5 0.1 distance_b_a_c = neighbour_distance_b_a + distance_a_c
401 796236 3412145520 4285.3 0.1 if(distance_b_a_c < cutoff_distance): # not too for to go
402 593352 2514800052 4238.3 0.1 node_b_update = True
403
404 ## Affinity distances update
405 41564609 164585250189 3959.7 6.8 if node_b_update:
406 818709 3933555120 4804.6 0.2 node_b_distances[node_c] = (distance_b_a_c, node_a)
407 818709 4151464335 5070.7 0.2 if((node_b.type == Atom.BINDING_SITE) and (node_c.type == Atom.BINDING_SITE)):
408 104293 1704446289 16342.9 0.1 node_b_chemical.add_affinityDistance(node_b, node_c, self.chemistry.affinity(node_b.data, node_c.data))
409 818709 3557529531 4345.3 0.1 node_b_changed = True
410
411 # If any of node b's rows have exceeded the cutoff distance, then remove them
412 42350234 197075504439 4653.5 8.1 for node_c, (distance_b_c, node_after_b) in node_b_distances.items(): # Can't use iteritems() here, as deleting from the dictionary
413 41838114 180297579789 4309.4 7.4 if(distance_b_c > cutoff_distance):
414 206296 894881754 4337.9 0.0 del node_b_distances[node_c]
415 206296 860508045 4171.2 0.0 node_b_changed = True
416
417 ## Affinity distances update
418 206296 4698692217 22776.5 0.2 node_b_chemical.del_affinityDistance(node_b, node_c)
419
420 # If we've modified node_b's distance table, tell its chemical to update accordingly
421 512120 2130466347 4160.1 0.1 if(node_b_changed):
422 217858 1201064454 5513.1 0.0 node_b_chemical.nodes_changed.add(node_b)
423
424 # Remove any neighbours that have infinite distance (have just unbound)
425 ## TODO: not sure what difference it makes to do this here rather than above (after updating self.node_distances for neighbours)
426 ## but doing it above seems to break the walker's movement
427 737753 3830386968 5192.0 0.2 for (node_b, neighbour_distance_b_a) in self.neighbours[node_a].items(): # Can't use iteritems() here, as deleting from the dictionary
428 512120 2249770068 4393.1 0.1 if(neighbour_distance_b_a > cutoff_distance):
429 150 747747 4985.0 0.0 del self.neighbours[node_a][node_b]
430
431 ## Affinity distances update
432 150 2148813 14325.4 0.0 self.del_affinityDistance(node_a, node_b)
self.node_distances
。这是一个将节点映射到路由表的字典。节点是我定义的对象。路由表是一个字典,将节点映射到 (distance, next_node) 的元组。距离是node_a到node_b的图距离,next_node是node_a的邻居,你必须先去,在node_a和node_b之间的路径上。 None 的 next_node 表示 node_a 和 node_b 是图邻居。例如,距离矩阵的样本可以是:
self.node_distances = { node_1 : { node_2 : (2.0, None),
node_3 : (5.7, node_2),
node_5 : (22.9, node_2) },
node_2 : { node_1 : (2.0, None),
node_3 : (3.7, None),
node_5 : (20.9, node_7)},
...etc...
self.neighbours
矩阵类似于
self.node_distances
,但包含有关网络中直接链接(边)的信息。通过化学 react ,
self.neighbours
不断被外部修改为该功能。这就是网络拓扑变化的来源。
propagate_distances_node()
执行
distance-vector routing protocol 的一步。给定一个节点
node_a
,该函数确保
node_a
的邻居在距离矩阵中正确(拓扑变化)。然后,该函数将
node_a
的路由表发送到网络中
node_a
的所有直接邻居。它将
node_a
的路由表与每个邻居自己的路由表集成在一起。
propagate_distances_node()
函数被重复调用,直到距离矩阵收敛。维护了一组
self.nodes_changed
,其中包含自上次更新以来已更改其路由表的节点。在我的算法的每次迭代中,都会选择这些节点的随机子集,并对它们调用
propagate_distances_node()
。这意味着节点异步和随机地传播它们的路由表。当集合
self.nodes_changed
为空时,该算法收敛于真实距离矩阵。
add_affinityDistance
和
del_affinityDistance
)是距离矩阵的(小)子矩阵的缓存,由程序的不同部分使用。
self
是一个代表化学物质的对象。
self.node_distances.keys()
中的节点是构成化学物质的原子。
self.node_distances[node_x].keys()
中的节点是来自化学物质的节点,并且可能来自与化学物质结合(并与之 react )的任何化学物质的节点。
node_x == node_y
(根据@Sven Marnach 的评论)替换
node_x is node_y
的每个实例,但它减慢了速度! (我没想到!)
is
绝对快于
==
。使用
CProfile ,我的代码
==
花费了 34.394s,但使用
is
,它花费了 33.535s(我可以确认这是噪音)。
最佳答案
node_after_b == node_a
将尝试调用 node_after_b.__eq__(node_a)
:
>>> class B(object):
... def __eq__(self, other):
... print "B.__eq__()"
... return False
...
>>> class A(object):
... def __eq__(self, other):
... print "A.__eq__()"
... return False
...
>>> a = A()
>>> b = B()
>>> a == b
A.__eq__()
False
>>> b == a
B.__eq__()
False
>>>
Node.__eq__()
。
#!/usr/bin/env python
# test.py
class A(object):
def __init__(self, id):
self.id = id
class B(A):
def __eq__(self, other):
return self.id == other.id
@profile
def main():
list_a = []
list_b = []
for x in range(100000):
list_a.append(A(x))
list_b.append(B(x))
ob_a = A(1)
ob_b = B(1)
for ob in list_a:
if ob == ob_a:
x = True
if ob is ob_a:
x = True
if ob.id == ob_a.id:
x = True
if ob.id == 1:
x = True
for ob in list_b:
if ob == ob_b:
x = True
if ob is ob_b:
x = True
if ob.id == ob_b.id:
x = True
if ob.id == 1:
x = True
if __name__ == '__main__':
main()
Timer unit: 1e-06 s
File: test.py Function: main at line 10 Total time: 5.52964 s
Line # Hits Time Per Hit % Time Line Contents
==============================================================
10 @profile
11 def main():
12 1 5 5.0 0.0 list_a = []
13 1 3 3.0 0.0 list_b = []
14 100001 360677 3.6 6.5 for x in range(100000):
15 100000 763593 7.6 13.8 list_a.append(A(x))
16 100000 924822 9.2 16.7 list_b.append(B(x))
17
18 1 14 14.0 0.0 ob_a = A(1)
19 1 5 5.0 0.0 ob_b = B(1)
20 100001 500454 5.0 9.1 for ob in list_a:
21 100000 267252 2.7 4.8 if ob == ob_a:
22 x = True
23 100000 259075 2.6 4.7 if ob is ob_a:
24 x = True
25 100000 539683 5.4 9.8 if ob.id == ob_a.id:
26 1 3 3.0 0.0 x = True
27 100000 271519 2.7 4.9 if ob.id == 1:
28 1 3 3.0 0.0 x = True
29 100001 296736 3.0 5.4 for ob in list_b:
30 100000 472204 4.7 8.5 if ob == ob_b:
31 1 4 4.0 0.0 x = True
32 100000 283165 2.8 5.1 if ob is ob_b:
33 x = True
34 100000 298839 3.0 5.4 if ob.id == ob_b.id:
35 1 3 3.0 0.0 x = True
36 100000 291576 2.9 5.3 if ob.id == 1:
37 1 3 3.0 0.0 x = True
vmstat 10 100
Yes, I had previously played with sys.setcheckinterval. I changed it to 1000 (from its default of 100), but it didn't do any measurable difference. Disabling Garbage Collection has helped - thanks. This has been the biggest speedup so far - saving about 20% (171 minutes for the whole run, down to 135 minutes) - I'm not sure what the error bars are on that, but it must be a statistically significant increase. – Adam Nellis Feb 9 at 15:10
I think the Python GC is based on reference count. From time to time it will check the reference count for every instance; since you are traversing these huge in-memory structures, in your particular case the GC default frequency (1000 cycles?) is away too often - a huge waste. – Yours Truly Feb 10 at 2:06
关于python - 优化Python字典访问代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4900747/
我只想国家和资本化的值(value)。 这是我的完整代码: cities = { 'rotterdam': { 'country': 'netherlands',
想更好地了解如何比较对象类型的键。 dicOverall.exists(dic2) 返回 False,而 dicOverall.exists(dic1) 返回 True。我不太确定 .Exists 如
我是编程和 python 的新手,我不知道如何解决这个问题。 my_dict = {'tiger': ['claws', 'sharp teeth', 'four legs', 'stripes'
这个问题已经有答案了: Accessing an object property with a dynamically-computed name (19 个回答) 已关闭 8 年前。 我引用了这篇文
希望有人能帮忙。我正在使用 Python,我希望能够执行以下操作。 我有一组对象(例如形状)和一系列作用于这些对象的命令。命令的格式为命令字符串,后跟可变数量的参数,可以是字符串或整数 例如形状“矩形
我在文件中保存了一本字典。我从 python 交互式 shell 将字典加载到内存中,我的系统监视器显示 python 进程消耗了 4GB。以下命令提供以下输出: size1 = sys.getsiz
如果我运行以下代码: import json foo = [ { "name": "Bob", "occupation": "", "stand
我尝试获取列名及其索引,并将结果保存为数据框或字典: df <- data.frame(a=rnorm(10), b=rnorm(10), c=rnorm(10)) 我该怎么做?谢谢。 column
我正在尝试获取输入,如果字典 logins 有一个与我的输入匹配的键,我想返回该键的值。 logins = { 'admin':'admin', 'turtle':'password1
在 Perl 世界中有一个很棒的东西叫做 CPAN .它是开源 Perl 库的大型存储。 我使用来自 CPAN 的模块,我已经发布了 several distributions myself . 我使
这个问题已经有答案了: Is there a Python dict without values? (3 个回答) 已关闭 3 年前。 我有一个问题,我想跟踪大量值。如果我从未遇到过该值,我将执行操
想知道这是否可能。 我们有一个第 3 方库,其中包含有关用户的识别信息... 与库的主要交互是通过一个以字符串为键的 HashTable,并返回该键的信息对象图。 问题是, key 显然是区分大小写的
我是 .NET 编程的新手。对不起,如果这个问题以前被问过。 我目前正在学习 F#。 Dictionary、Hashtable 和 Map 之间有什么区别?我应该什么时候使用? 我还有一个标题中没有提
我正在尝试使用SVM进行3类分类。为此,我正在SVM培训期间准备词汇表。但是,由于我在SVM预测期间获得随机结果,因此我怀疑我的词汇创建方法中存在一些问题。我创建词汇的代码如下: //Mat trai
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
假设我有一个以下形式的嵌套字典: {'geo': {'bgcolor': 'white','lakecolor': 'white','caxis': {'gridcolor': 'white', 'l
我有一个 java 应用程序,每秒启动和停止数亿个项目(从外部脚本调用)多次。 Input: String key Output: int value 此应用程序的目的是在从未永远改变的Map(约30
我正在尝试找出字典与集合和数组相比的相对优势和功能。 我发现了一篇很棒的文章here但找不到一个简单的表格来比较所有不同的功能。 有人知道吗? 最佳答案 请参阅下表,对集合和字典进行有用的比较。 (该
我想要一个字典,它可以为字典中没有的任何键返回一个指定的值,例如: var dict = new DictWithDefValues("not specified"); dict.Add("bob78
我是 python 新手,目前仍在学习如何处理列表和字典。 我有这两个功能 def food_database(item_name, size_serv, calorie_serv, prot
我是一名优秀的程序员,十分优秀!