- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想将许多操作“融合”在一起。假设有 3 种可能的操作:
sq = lambda x: x**2
add = lambda x: x+3
mul = lambda x: x*5
我还有一系列操作:
ops = [add, sq, mul, sq]
然后我可以通过这些操作创建一个函数:
def generateF(ops):
def inner(x):
for op in ops:
x = op(x)
return x
return inner
f = generateF(ops)
f(3) # returns 32400
fastF = lambda x: (5*(x+3)**2)**2
f
和 fastF
执行相同的操作,但 fastF
比 f
快 1.7-2 倍左右根据我的基准,这是有道理的。我的问题是,如何编写 generateF
函数来返回与 fastF
一样快的函数?这些操作仅限于基本操作,如 __add__
、__mul__
、__matmul__
、__rrshift__
等(基本上是 numeric operations ) 。 generateF
可以花您想要的时间,因为它会在到达热代码之前完成。
上下文是,这是我的库的一部分,因此我可以定义每个合法操作,从而确切地知道它们是什么。操作定义不是由最终用户随机提供给我们的(用户只能选择操作的顺序),因此我们可以利用有关它们的所有外部知识。
这可能看起来像是过早的优化,但事实并非如此,因为 f
是热代码。放弃使用 C 不是一个选择,因为操作可能很复杂(想想 PyTorch 张量乘法),并且 x 可以是任何类型。目前,我正在考虑修改 python 的字节码,但这非常不愉快,因为每个 Python 版本的字节码规范都会发生变化,所以我想在深入讨论该解决方案之前先在这里询问。
最佳答案
这是从给定函数的字节码合成新函数的非常hacky版本。基本技术是仅在第一个函数的开头保留 LOAD_FAST 操作码,并在最后一个函数的末尾之外去除 RETURN_VALUE 操作码。这使得在函数(最初的)之间的堆栈上操作的值。完成后,您不会进行任何函数调用。
import dis, inspect
sq = lambda x: x**2
add = lambda x: x+3
mul = lambda x: x*5
ops = [add, sq, mul, sq]
def synthF(ops):
bytecode = bytearray()
constants = []
stacksize = 0
for i, op in enumerate(ops):
code = op.__code__
# works only with functions having one argument and no other vars
assert code.co_argcount == code.co_nlocals == 1
assert not code.co_freevars
stacksize = max(stacksize, code.co_stacksize)
opcodes = bytearray(code.co_code)
# starts with LOAD_FAST argument 0 (i.e. we're doing something with our arg)
assert opcodes[0] == dis.opmap["LOAD_FAST"] and opcodes[1] == 0
# ends with RETURN_VALUE
assert opcodes[-2] == dis.opmap["RETURN_VALUE"] and opcodes[-1] == 0
if bytecode: # if this isn't our first function, our variable is already on the stock
opcodes = opcodes[2:]
# adjust LOAD_CONSTANT opcodes. each function can have constants,
# but their indexes start at 0 in each function. since we're
# putting these into a single function we need to accumulate the
# constants used in each function and adjust the indexes used in
# the function's bytecode to access the value by its index in the
# accumulated list.
offset = 0
if bytecode:
while True:
none = code.co_consts[0] is None
offset = opcodes.find(dis.opmap["LOAD_CONST"], offset)
if offset < 0:
break
if not offset % 2 and (not none or opcodes[offset+1]):
opcodes[offset+1] += len(constants) - none
offset += 2
# first constant is always None. don't include multiple copies
# (to be safe, we actually check that)
constants.extend(code.co_consts[none:])
else:
assert code.co_consts[0] is None
constants.extend(code.co_consts)
# add our adjusted bytecode, cutting off the RETURN_VALUE opcode
bytecode.extend(opcodes[:-2])
bytecode.extend([dis.opmap["RETURN_VALUE"], 0])
func = type(ops[0])(type(code)(1, 1, 0, 1, stacksize, inspect.CO_OPTIMIZED, bytes(bytecode),
tuple(constants), (), ("x",), "<generated>", "<generated>", 0, b''),
globals())
return func
f = synthF(ops)
assert f(3) == 32400
恶心,还有很多警告(在注释中指出),但它有效,并且应该与您的表达式一样快,因为它编译为几乎相同的字节码。它需要一些工作来支持连接更复杂的函数。
关于python - 如何将多个Python函数融合在一起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69949048/
我输入了一个包含两个元素的 vector 。然后我将另一个元素 push_back 到它,并期望什么结果类型也是一个 vector 。但事实并非如此。 例子: typedef boost::fusio
首先让我先说,我以前在这里问过类似的问题,但从来没有得到解决我缺乏知识/问题的好答案。 首先,让我从一个分支策略提案开始。这就是我们的工作,我很高兴听到其他评论,以及为什么这很糟糕。但要明白它通常对我
所以我将一个带有 javascript 的字符串发送到 php 页面: if(cp.value!=''){ s+=cp.name +" LIKE '%"+ cp.value +"%'";
我有一个简单的问题,我该如何使用 which和 which.max同时。 我想选择最大值epnum为行 id == B13639J2 . 我需要检索 row number因为我需要对变量进行一些手动更
我想将带有 Groovy 脚本的文件上传到 Confluence。 As this Pythonscript example!我开始将代码翻译成 groovy, // Groovy def serve
我有一个融合 vector ,其元素具有多个不同类型的成员数据,我想创建一个新的融合 vector ,它将仅投影特定的数据成员。我已经对此进行了一段时间的研究,但没有任何进展。 #include #
我正在尝试使用 Python 的 xmlrpclib 创建一个新的页面以汇合。我已经知道如何更新现有页面的内容,但如何创建一个全新的页面? 我使用了以下脚本来更新内容: import xmlrpcli
我正在使用 Pow 在 Mac OS X 上为 Rack 应用程序提供服务。http://myapp.dev正确显示应用程序。在同一台机器上,我使用 VMware Fusion 运行 Windows
我检查了 Cassandra 和 Infinispan 的主要特性。它们似乎具有并提供非常相似的特性和功能: NoSQL 数据存储 坚持 去中心化 支持复制 可扩展性 容错 MapReduce 支持
我在Drupal 7网站中使用Search API和Elasticsearch Connector。我已经在AWS中托管了elasticsearch。搜索完美无误。但是我想像在Drupal.org搜索
我最近重新打开了几年前参与的一个项目。我写了一个小的 python 脚本来构建项目。我想将其移植到 CMake。 我遇到的问题是脚本使用了 pkg-config在 linux 上找到 fuse 头文件
我正在尝试访问 Yelp fusion API。我正在关注documentation并来到这段代码: const request = require('request'); // As you can
这是一个 vanilla Ubuntu 16.04 LTS,准确地说是基于 Xubuntu core。所以我需要自己安装包。除了 meld 之外,一切都很顺利,开始时,我会得到: (meld:4188
我正在尝试对惰性求值在 Java 流 API 中的应用形成一个简洁而连贯的理解。 这是我目前的理解: 元素仅在需要时才被消耗,即流是惰性的,中间操作也是惰性的,例如过滤器,仅在需要时进行过滤。 中间操
我使用 conluent jdbc-sink 将数据从 kafka 加载到 oracle。 但是我用数据编写了关于值(value)的模式。 我不想用数据编写模式,如何在 kafka 主题上编写模式,然
我在这里编写了一个 2D 融合套索代码。 [m n] = size(circle); cvx_begin variable theta(m, n); minimize( norm(ci
目前我正在开发一个使用 dx9 创建叠加层的应用程序。现在我遇到了一个问题,自从我将 Windows 10 升级到最新版本(Creators Update)后,它无法使用 alpha channel
我正在尝试编写类似 fiber 的代码,这样我就可以进入任务并从中退出。我试过的代码: class TaskActivity { CancellationTokenSource _m=new
我使用 NPM 在 React.js 中创建了一个前端。作为 IDE,我在这里使用 IntelliJ IDEA。该项目将使用我单独创建的 Spring Boot 编写的后端,也在 IntelliJ I
Cassandra 连接器在融合升级到 3.3.0 后失败。 Cassandra驱动的版本是3.3。堆栈如下。 [2017-09-14 08:56:28,123] ERROR java.lang.re
我是一名优秀的程序员,十分优秀!