- 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/
Chisel 是否支持设计中的多个时钟?如果我想实现一个异步 fifo,如何在 Chisel 中实现呢? 最佳答案 是的,Chisel 支持设计中的多个时钟。如果你想使用异步fifo,你可以导入模块C
当在单个进程上使用 FIFO 时,看起来两端都打开然后关闭,不可能重用 FIFO。任何重新打开封闭端的尝试都会失败,或者返回的文件描述符无用。 是否有可能解决此问题,还是我们必须保持 FIFO 的两端
考虑以下场景: 名为 test 的 FIFO被 build 。在一个终端窗口 (A) 中,我运行 cat test 。现在可以在窗口 B 中写入并在窗口 A 中获取输出。也可以终止进程 A 并重新启动
是否有某种方法可用于在真正的 FIFO 中使用 Amazon SQS 消息?我尝试从配置延迟消息传递,但这没有帮助。 最佳答案 亚马逊SQS刚刚获得FIFO Queues with Exactly-O
我有一个非常简单的基本程序,它有两个进程,第一个是parent,第二个是child。 子进程应该向 FIFO 写入一些内容。在所有写作工作完成后(在 child 被终止后)。然后父进程应该读取所有
在 C 中使用 epoll,有什么方法可以让从 FIFO 读取的程序检测到写入同一 FIFO 的程序已将其关闭? 我以为这会生成一个 EPOLLHUP 事件,但显然它不会。 例子:我有一个读者和一个作
在 bash 脚本中,我使用管道将命令的输出传递给另一个命令的输入: $ output_com | input_com output_com 比 input_com 慢。在我的脚本中,在input_c
我试图在 3.12 内核中自己实现 FIFO 调度程序,我无法找到 FIFO 文件的位置...就像 rt.c 位于/kernel/sched/rt.c 最佳答案 您在寻找哪个调度程序? Linux 有
这个问题在这里已经有了答案: Implementing FIFO using LIFO (2 个答案) 关闭 6 年前。 我了解使 Push 操作昂贵或 pop 操作昂贵的传统方法。 如何让push
我正在学习 Linux 中的管道编程,但无法理解管道/FIFO 管理。 我写了一个小程序来打开我创建的 FIFO(在执行程序之前,我在终端中执行了 mkfifo newfifo)。然后我反复读取并转储
我有一个写入标准输出的进程,我希望能够在运行 tail -f 时通过 grepping 查找各种字符串来监视输出。执行此操作的一种方法是写入一个普通文件,然后对文件进行尾部搜索一个字符串,然后对另一个
我想将一些数据输出到管道并让其他进程逐行处理数据。这是一个玩具示例: mkfifo pipe cat pipe& cat >pipe 现在我可以输入我想要的任何内容,按下回车后我立即看到同一行。但是如
我正在尝试开发一个程序来播放和录制一些 rtmp 流。该程序是在Qt中开发的。 我正在使用 rtmpdump 和 mplayer。因为两者都在单独的进程中运行,所以我使用 fifo 将流从 rtmpd
所以我开始构建我的本地 iOS 设备环境。我已经完全设置并运行了我的模拟器环境。我已经通过 iOS 开发人员为应用程序正确设置了我的分发和配置文件。在尝试运行该应用程序时,我遵循以下步骤:使用 USB
S3-FIFO 本文作为下一篇缓存文章的预备知识。 背景 基于LRU和FIFO的驱逐 FIFO和LRU都是经典的缓存驱逐算法,在过去几十年中也出现了很多追求更高效率的驱逐算法,如ARC, 2Q
我可以为单向通信创建一个 FIFO。但我该如何进行双向沟通呢?我可以创建一个可以充当发送方的 C 文件,并打开另一个充当接收方的终端。但如何建立双向通信呢?谢谢! 最佳答案 你不能。尝试一个套接字。考
考虑下表: Id Verb Qty Price `1 Buy 6 10.0 `2 Sell 5 11.0 `3 Buy 4 10.0 `4 Sell 3 11.0 `5 Sell 8 9.0 `6
我有两个进程(“发送者”和“接收者”)需要通过 transient 单向 FIFO 通信管道在单台机器上本地进行通信。这是我想要发生的事情(使用更接近 Unix 域套接字的语言): 发送者在已知地址“
好的,所以我正在使用 FIFO,并且我正在尝试构建一个小型库以在 future 的程序中使用。 它应该能够创建一个命名管道,读取它并在其中写入。 我能够完成所有这些功能,但它没有正确读取。问题如下:
数组有循环缓冲区版本吗?假设一次最大推送元素的数量已知,我是否必须派生自己的 FIFO 队列来提高性能? 这是我尝试过的: 循环实现: function CBuf(n) { var ctrPu
我是一名优秀的程序员,十分优秀!