- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要某种缓存来存储 Cython 中函数 f
的结果以供将来重用。一个简单的 FIFO 缓存策略可以在缓存已满时丢弃最近最少计算的结果。每次从 Python 调用另一个使用缓存并调用 f
的函数时,我都需要重新初始化缓存。我使用包裹在扩展类型中的 std::map
想出了以下解决方案:
# distutils: language = c++
import sys
import time
from libcpp.map cimport map as cppmap
from libcpp.utility cimport pair as cpppair
from libcpp.queue cimport queue as cppqueue
from cython.operator cimport dereference as deref
ctypedef cpppair[long, long] mapitem_t
ctypedef cppmap[long, long].iterator mi_t
cdef class Cache_map:
"""Cache container"""
cdef:
cppmap[long, long] _cache_data
cppqueue[long] _order
long _cachesize
long _size
def __init__(self, long cachesize=100):
self._cachesize = cachesize
self._size = 0
cdef mi_t setitem(
self, mi_t it, long key, long value):
"""Insert key/value pair into cache and return position"""
if self._size >= self._cachesize:
self._cache_data.erase(self._order.front())
self._order.pop()
else:
self._size += 1
self._order.push(key)
return self._cache_data.insert(it, mapitem_t(key, value))
@property
def cache_data(self):
return self._cache_data
cdef long f(long x):
"""Expensive function"""
time.sleep(0.01)
return x**2
cdef long cached_f(long x, Cache_map Cache):
cdef mi_t search = Cache._cache_data.lower_bound(x)
if search != Cache._cache_data.end() and x == deref(search).first:
return deref(search).second
return deref(Cache.setitem(search, x, f(x))).second
def use_cache():
# Output container
cdef list cache_size = []
cdef list timings = []
cdef list results = []
cdef long i, r
cdef Cache_map Cache = Cache_map(10) # Initialise cache
cache_size.append(sys.getsizeof(Cache))
go = time.time()
for i in range(100):
# Silly loop using the cache
for r in range(2):
results.append(cached_f(i, Cache))
timings.append(time.time() - go)
go = time.time()
cache_size.append(sys.getsizeof(Cache))
go = time.time()
return cache_size, timings, results
虽然这在原则上可行,但它有一些缺点:
cached_f
来包装 f
(不太可重用)Cache
传递给 cached_f
(不必要的昂贵???)Cached_map
被显式写入以缓存来自 f
的结果(不是很可重用)我想这是一个相当标准的任务,那么有更好的方法吗?
例如,我尝试将指向缓存的指针传递给 cached_f
但似乎我无法创建指向扩展类型对象的指针?以下内容:
cdef Cache_map Cache = Cache_map(10)
cdef Cache_map *Cache_ptr
Cache_ptr = &Cache
抛出 cache_map.pyx:66:16:无法获取 Python 变量“Cache”的地址
。
最佳答案
我认为从软件工程的角度来看,将函数(在 C/cdef-Cython 中是函数指针/仿函数)及其内存捆绑在一个对象/类中是个好主意。
我的方法是编写一个 cdef 类(我们称之为 FunWithMemoization
),它有一个函数指针和一个用于存储已知结果的内存数据结构。
因为生命太短暂,无法用 Cython 编写 c++ 代码,所以我用纯 c++ 编写了 memoization-class(完整代码可以在下面进一步找到),这或多或少与您的方法非常相似(但是使用unordered_map
) 并用 Cython 包装/使用它:
%%cython -+
from libcpp cimport bool
cdef extern from *:
"""
// see full code bellow
"""
struct memoization_result:
long value;
bool found;
cppclass memoization:
memoization()
void set_value(long, long)
memoization_result find_value(long key)
ctypedef long(*f_type)(long)
cdef long id_fun(long x):
return x
cdef class FunWithMemoization:
cdef memoization mem
cdef f_type fun
def __cinit__(self):
self.fun = id_fun
cpdef long evaluate(self, long x):
cdef memoization_result look_up = self.mem.find_value(x)
if look_up.found:
return look_up.value
cdef long val = self.fun(x)
self.mem.set_value(x, val)
return val
我已经使用 id_fun
来默认初始化 fun
成员,但是我们需要进一步的功能来使 FunWithMemoization
有用,例如:
import time
cdef long f(long x):
"""Expensive function"""
time.sleep(0.01)
return x**2
def create_f_with_memoization():
fun = FunWithMemoization()
fun.fun = f
return fun
显然还有其他方法可以创建有用的FunWithMemoization
,可以使用ctypes
来获取函数地址或这个receipt .
现在:
f = create_f_with_memoization()
# first time really calculated:
%timeit -r 1 -n 1 f.evaluate(2)
#10.5 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)
# second time - from memoization:
%timeit -r 1 -n 1 f.evaluate(2)
1.4 µs ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)
完整代码:
%%cython -+
from libcpp cimport bool
cdef extern from *:
"""
#include<unordered_map>
#include <queue>
struct memoization_result{
long value;
bool found;
};
class memoization{
private:
std::unordered_map<long, long> map;
std::queue<long> key_order;
size_t max_size;
public:
memoization(): max_size(128){}
void set_value(long key, long val){
//assumes key isn't yet in map
map[key]=val;
key_order.push(key);
if(key_order.size()>max_size){
key_order.pop();
}
}
memoization_result find_value(long key) const{
auto it = map.find(key);
if(it==map.cend()){
return {0, false};
}
else{
return {it->second, true};
}
}
};
"""
struct memoization_result:
long value;
bool found;
cppclass memoization:
memoization()
void set_value(long, long)
memoization_result find_value(long key)
ctypedef long(*f_type)(long)
cdef long id_fun(long x):
return x
cdef class FunWithMemoization:
cdef memoization mem
cdef f_type fun
def __cinit__(self):
self.fun = id_fun
cpdef long evaluate(self, long x):
cdef memoization_result look_up = self.mem.find_value(x)
if look_up.found:
return look_up.value
cdef long val = self.fun(x)
self.mem.set_value(x, val)
return val
import time
cdef long f(long x):
"""Expensive function"""
time.sleep(0.01)
return x**2
def create_f_with_memoization():
fun = FunWithMemoization()
fun.fun = f
return fun
关于python - 函数结果的 Cython FIFO 缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62159140/
c 不做边界检查。那么cython是如何检查是否编译成c的呢? %%cython --annotate cimport cython @cython.boundscheck(True) cpdef m
可以直接声明用于 Cython 构造函数? 据我了解,这是可能的: # Cython cdef int[3] li = [1, 2, 3] # C++ int[3] li = {1, 2, 3} 但
所以,如果你有一个头文件。 %%file test.h struct mystruct{ int i; int j; }; 然后你将它包装在 Cython 中: cdef extern fr
我正在构建一个独立于平台的 cython 项目,我想根据正在使用的编译器传递编译器参数。我可以猜测基于平台的编译器,或者假设它与用于 Python 的编译器相同,但不能保证匹配。通常我注入(injec
我使用诗歌构建我的 cython 包。我在所有函数和类中都有 NumPy 风格的文档字符串。我现在要做的是添加 Sphinx 自动文档并发布在 Read the Docs。 我已阅读此主题 How d
赛通 libcpp模块包含 priority_queue 的模板,这很好,除了一件事:我不能通过自定义比较器(或者,至少,我不知道如何)。 我需要这个,因为我需要 priority_queue做一个a
以下代码定义了一个简单的 Cython 函数(为方便起见,使用 Ipython 魔法)。 %load_ext cython %%cython def f(float x, float y=2):
我正在尝试使用 cython 进行复数计算。在示例代码中,我想计算复数的复指数函数。问题是我不知道如何将我的整数乘以虚数单位。python的虚数单位1.0j乘以cython执行时报错。 这是我的代码:
在这里停留在一些基本的 Cython 上 - 在 Cython 中定义字符串数组的规范且有效的方法是什么? 具体来说,我想定义一个定长常量数组char . (请注意,此时我不想引入 NumPy。) 在
是否有可能,如果是,如何确定 Cython 中整数数据类型的大小(以位为单位)? 我正在尝试做这样的事情,以获得整数大小: cdef WORD_BITS = 0 IF sizeof(unsigned
我只是想打印 cython 变量的地址,但我无法绕过错误消息: cdef int myvar print &myvar 抛出 Cannot convert 'int *' to Python obje
我有一个 C 头文件,它在宏中定义了一个函数。我需要从 Cython 调用它。有没有办法在 Cython 中使用宏并使其完全扩展?我已经有了 C 类型的参数。 我尝试像使用函数一样使用 cdef,我认
令人惊讶的是,我似乎找不到通过名称获取结构体元素的单个示例(无论是在网络上还是在 cython 示例中)。 所以我收到了一个指向 C 函数结构体的指针,并且想要一一访问这些元素并将它们重新打包到 py
我尝试围绕 C++ 库编写一个 Cython 包装器 http://primesieve.org/ 它包装了一个函数count。到目前为止,它可以正确安装 python setup.py instal
我正在尝试将 cython 模块 data.pyx 导入另一个 cython 模块 user.pyx。一切都编译得很好,但是当我尝试在 python 模块中调用 user.pyx 时,我收到错误“Im
更新:内存 View 获胜。Cython 使用类型化内存 View :0.0253449 特别感谢 lothario,他指出了几个关键的变化。 荒谬。当然现在的问题是,似乎不能对它们做太多算术(加法和
我有一个使用 memoryview 数组的 cython 模块,即... double[:,:] foo 我想使用多处理并行运行这个模块。但是我得到了错误: PicklingError: Can't
我正在尝试使用 Cython 加速 PEP 484 类型的 python 脚本。我想保持一些语义和可读性。 之前,我有一个 Flags = int def difference(f1: Flags,
这个问题已经有答案了: Collapse multiple submodules to one Cython extension (5 个回答) 已关闭 3 年前。 我在一个包中有多个 .py 文件
我已经能够在我的 .pyx 脚本上使用 cython 在 linux 上创建一个 .so 文件。我也可以成功地在我的 python 解释器上进行导入。 我的问题是如何在不使用 cython 的情况下将
我是一名优秀的程序员,十分优秀!