- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
假设有一个 A 类,并且有一个名为 lst
的 A 类实例列表。
假设我们要对列表中的每个实例一遍又一遍地调用类 A 的特定方法 m
数百万次,(实际示例:entity.游戏循环中的 update()
方法)。我们知道执行此操作的简单方法如下:
for obj in lst: obj.m()
然而,这种代码会让我们昏昏欲睡。于是我们想到使用map
的方式如下:
map(lambda obj: obj.m(), lst)
但是我们对上面的代码行进行了几次测试,结果发现它比我们简单的 for
循环要慢得多。有时它甚至慢 2 倍。然后我们自己想,“嗯,它可能更慢,因为 map
为所有函数调用构造了一个返回值列表并返回该列表”。
假设我们从名为 xrange
的惰性且内存高效的内置函数中获得灵感。大多数情况下,我们认为它是 range
的更酷版本。因此,我们定义了一个名为 xmap
的函数,它只是将一个函数应用于一个对象列表,而不构造一个返回值列表并返回它。实现如下:
def xmap(func, lst):
for obj in lst: func(obj)
非常酷,因为这个函数只是执行上面的 for
循环,只是它允许我们保持幻想并发送我们的 lambda 函数。我们认为这是完美的妥协。但是我们一丝不苟,所以我们决定制作 2 个脚本来测试我们代码的速度,看看我们是否真的比 map
快。
我们的第一个脚本将简单地使用 map
并无用地构造一个我们甚至不需要的列表。
script1.py
:
class A:
def m(self):
pass
lst = [A() for i in xrange(15)]
import time
start = time.time()
for i in xrange(1000000):
map(lambda obj: obj.m(), lst)
print time.time()-start, 'seconds'
我们的第二个脚本将使用 xmap
,我们相信它会更快,因为它不必构造一个包含 15 个返回值的列表 1,000,000 次并返回它.
script2.py
def xmap(func, lst):
for obj in lst: func(obj)
class A:
def m(self):
pass
lst = [A() for i in xrange(15)]
import time
start = time.time()
for i in xrange(1000000):
xmap(lambda obj: obj.m(), lst)
print time.time()-start, 'seconds'
我们终于完成了,很高兴看到我们的代码会快多少。然而,在对彼此运行这两个脚本几次之后,事实证明 script2.py
似乎并不比 script1.py
快。实际上,事实证明,script2.py
有时比 script1.py
运行时间更长。 xmap
似乎与 map
花费的时间差不多。
为什么我会得到这些结果?
C:\dev\py>python script1.py
14.7799999714 seconds
C:\dev\py>python script2.py
14.2170000076 seconds
C:\dev\py>python script1.py
12.1800000668 seconds
C:\dev\py>python script2.py
12.5759999752 seconds
C:\dev\py>python script1.py
14.3020000458 seconds
C:\dev\py>python script2.py
14.9490001202 seconds
C:\dev\py>python script1.py
14.6879999638 seconds
C:\dev\py>python script2.py
14.3139998913 seconds
我认为我至少应该优化 map
中的something 因为我没有构建返回值列表,但我的代码似乎没有快点我知道列表构建需要一些时间,因为我已经完成了以下操作:
>>> import timeit
>>> timeit.timeit('[]')
0.1297345953932106
>>> timeit.timeit('[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]')
0.6807682686160632
>>> timeit.timeit('[None,None,None,None,None,None,None,None,None,None,None,None,
None,None,None]')
0.7460120889200539
那么为什么我的 xmap
函数似乎并不比 map
快?
最佳答案
首先,也是最重要的一点:像这样的时间微优化只会让您感到困惑,因为您正在测量诸如函数之类的非常低级的开销。
不过,在这种情况下,我很确定问题在于,由于额外的 lambda
,您可能从 map/xmap
中获得的 yield 正在损失.如果您直接使用 A.m
,情况会好很多:
>>> %timeit for obj in lst: obj.m()
100000 loops, best of 3: 2.99 µs per loop
>>> %timeit [obj.m() for obj in lst]
100000 loops, best of 3: 3.5 µs per loop
>>> %timeit xmap(lambda obj: obj.m(), lst)
100000 loops, best of 3: 5.69 µs per loop
>>> %timeit xmap(A.m, lst)
100000 loops, best of 3: 3.32 µs per loop
FWIW,在我看来你的 xmap
最终会获胜:
>>> lst = [A() for i in xrange(10**3)]
>>> %timeit for obj in lst: obj.m()
1000 loops, best of 3: 198 µs per loop
>>> %timeit [obj.m() for obj in lst]
1000 loops, best of 3: 216 µs per loop
>>> %timeit xmap(lambda obj: obj.m(), lst)
1000 loops, best of 3: 353 µs per loop
>>> %timeit xmap(A.m, lst)
10000 loops, best of 3: 189 µs per loop
但我也不会太认真地对待这些数字。
当您说“那种代码 [即简单的 for 循环] 让我们休眠”时,我同意 - 编写简单的循环意味着您可以更快地完成编程并且可以更早上床 sleep 。
关于python - 为什么我的 'xmap' 函数并不比内置的 'map' 快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18994471/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!