- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
为了练习,我编写了一个XOR双链表
%%cython
from cpython.object cimport PyObject
from cpython.ref cimport Py_XINCREF, Py_XDECREF
from libc.stdint cimport uintptr_t
cdef class Node:
cdef uintptr_t _prev_xor_next
cdef object val
def __init__(self, object val, uintptr_t prev_xor_next=0):
self._prev_xor_next=prev_xor_next
self.val=val
@property
def prev_xor_next(self):
return self._prev_xor_next
@prev_xor_next.setter
def prev_xor_next(self, uintptr_t p):
self._prev_xor_next=p
def __repr__(self):
return str(self.val)
cdef class CurrentNode(Node):
cdef uintptr_t _node, _prev_ptr
def __init__(self, uintptr_t node, uintptr_t prev_ptr=0):
self._node = node
self._prev_ptr= prev_ptr
@property
def val(self):
return self.node.val
@property
def node(self):
ret=<PyObject *> self._node
return <Node> ret
@property
def prev_ptr(self):
return self._prev_ptr
cdef CurrentNode forward(self):
if self.node.prev_xor_next!=self._prev_ptr:
return CurrentNode(self.node.prev_xor_next^self._prev_ptr, self._node)
cdef CurrentNode backward(self):
if self._prev_ptr:
pp=<PyObject*>self._prev_ptr
return CurrentNode(self._prev_ptr, self._node^(<Node> pp).prev_xor_next)
def __repr__(self):
return str(self.node)
cdef class XORList:
cdef PyObject* first
cdef PyObject* last
cdef int length
def __init__(self):
self.length=0
@property
def head(self):
return (<Node> self.first)
@property
def tail(self):
return (<Node> self.last)
cdef append(self, object val):
self.length+=1
#empty list
if not self.first:
t=Node(val)
tp=(<PyObject*> t)
self.first=tp
Py_XINCREF(tp)
self.last=tp
Py_XINCREF(tp)
#not empty
else:
new_node=Node(val, <uintptr_t> self.last)
new_ptr=<PyObject*> new_node
cur_last=<Node>self.last
cur_last.prev_xor_next=cur_last.prev_xor_next^(<uintptr_t> new_ptr)
Py_XINCREF(new_ptr)
self.last=new_ptr
Py_XINCREF(new_ptr)
cpdef reverse(self):
temp=self.last
self.last=self.first
self.first=temp
def __repr__(self):
return str(list(iter_XORList(self)))
def __len__(self):
return self.length
def iter_XORList(l):
head=<PyObject*>l.head
cur=CurrentNode(<uintptr_t> head)
while cur:
yield cur
cur=cur.forward()
import time
start=time.time()
cdef XORList l=XORList()
for i in range(100000):
l.append(i)
print('time xor ', time.time()-start)
start=time.time()
l1=[]
for i in range(100000):
l1.append(i)
print('time regular ', time.time()-start)
time xor 0.10768294334411621
time regular 0.010972023010253906
700003 function calls in 1.184 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 1.184 1.184 <string>:1(<module>)
1 0.039 0.039 1.184 1.184 _cython_magic_14cf45d2116440f3df600718d58e4f95.pyx:108(list_check)
100000 0.025 0.000 0.025 0.000 _cython_magic_14cf45d2116440f3df600718d58e4f95.pyx:11(__init__)
99999 0.019 0.000 0.019 0.000 _cython_magic_14cf45d2116440f3df600718d58e4f95.pyx:16(__get__)
99999 0.018 0.000 0.018 0.000 _cython_magic_14cf45d2116440f3df600718d58e4f95.pyx:19(__set__)
1 0.000 0.000 0.000 0.000 _cython_magic_14cf45d2116440f3df600718d58e4f95.pyx:60(__init__)
100000 0.937 0.000 0.999 0.000 _cython_magic_14cf45d2116440f3df600718d58e4f95.pyx:70(append)
100000 0.113 0.000 1.146 0.000 line_profiler.py:111(wrapper)
1 0.000 0.000 1.184 1.184 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
100000 0.018 0.000 0.018 0.000 {method 'disable_by_count' of '_line_profiler.LineProfiler' objects}
100000 0.015 0.000 0.015 0.000 {method 'enable_by_count' of '_line_profiler.LineProfiler' objects}
append
的调用,似乎大部分时间都花在了特殊方法上。
最佳答案
分析中的三个罪魁祸首是Node的__init__
(在这里是不可避免的),以及__get__
和__set__
的prev_xor_next
属性。我的观点是,您不希望使用prev_xor_next
属性(或者如果您这样做的话,它应该是只读的),因为它可以使Python内部的Cython内部访问。
无论是否删除该属性,都在此处使用Cython,以便可以直接写入基础C属性_prev_xor_next
。您可能需要在cdef Node cur_last
的开头(以及可能在其他函数中)设置append
,以确保Cython知道cur_last
的类型-我认为它应该可以解决,但是如果您得到
这项更改使我的速度提高了30%(即,它的速度仍然比常规列表慢,但这是一个明显的改进)。
我将概述一个更剧烈的变化,我可能应该在关于这个问题的第一个问题上提出建议。这确实是一个模糊的大纲,因此没有为使其工作而作任何努力。
AttributeErrors
完全在
Node
类的内部:不应在Python中使用它,并且
XORList
中所有
Nodes
的生存期都直接与列表绑定。因此,应该在销毁自己的
XORList
时破坏它们(或者如果列表缩小,等等),因此不必进行引用计数。因此,
XORList
应该是C结构而不是Python对象:
cdef struct Node:
uintptr_t prev_xor_next
PyObject* val
# with associated constructor- and destructor-like functions:
cdef Node* make_node(object val, uintptr_t prev_xor_next):
cdef Node* n = <Node*>malloc(sizeof(Node))
n.val = <PyObject*>val
Py_XINCREF(n.val)
n.prev_xor_next = prev_xor_next
return n
cdef void destroy_node(Node* n):
Py_XDECREF(n.val)
free(n)
Node
需要一个
XORList
函数,该函数循环遍历在每个
__dealloc__
上调用
destroy_node
的列表(在您的版本中也需要一个
Node
函数!)
__dealloc__
需要保持Cython类,因为这是您的“迭代器”界面。它显然不再可以从
CurrentNode
继承。我将其更改为:
cdef class XORListIterator:
cdef Node* current_node
cdef XORList our_list
Node
的目的是确保
our_list
至少与
XORList
一样长-如果最终得到的
CurrentNode
迭代器不再存在,则
XORList
属性将无效。
current_node
不是
current_node
的所有者,因此不需要析构函数。
XORListIterator
所做的任何更改都不会完全使任何现有的
XORList
失效,直至崩溃。我怀疑这也是您当前版本的问题。
XORListIterators
仍然会保持竞争力,因为它是一个编写良好,高效的结构。请记住,
list
通常是简单的
list.append
,偶尔会有数组重新分配和复制。您总是需要创建一个新的Python对象(
Py_INCREF
)以及一些相关的引用计数。
Node
较小的内存分配的缺点,这对于链表结构是不可避免的。
append
的实现细节,不应向Python用户公开。
关于python - Cython实现不比纯python快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58617519/
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!