我正在尝试对几个文件的内容进行排序(有时会将一行从一个文件移到另一个文件中)
我想使用内置的自适应合并排序和list
的属性。我尝试从list
继承该方法,但我不知道它是否需要超过__len__
,__getitem__
和__setitem__
。是。我想要就地排序。
仅供参考,这是我的代码到目前为止(如果它有助于解释我在做什么),当我调用.sort()时,顺序不会改变。如果我添加我自己用python编写的bubble_sort方法,它可以工作,但速度非常慢:
class Memwrap(list):
def __init__(self, prefix, folder='.', chunksize=None):
fns = [fn for fn in os.listdir(folder) if fn.startswith(prefix)]
fns.sort()
self.files = [open(os.path.join(folder,fn), 'r+') for fn in fns]
self.mmaps = [mmap.mmap(f.fileno(), 0) for f in self.files]
self.sizes = [mm.size() for mm in self.mmaps]
if chunksize is None:
self.chunksize = len(self.mmaps[0].readline())
else:
self.chunksize = chunksize
def _mm_from_idx(self, idx):
bidx = self.chunksize*idx
lo = 0
for m,s in zip(self.mmaps, self.sizes):
hi = lo + s
if lo <= bidx < hi:
return bidx-lo, m
lo = hi
def __getitem__(self, idx):
bidx, mmap = self._mm_from_idx(idx)
return mmap[bidx:bidx+self.chunksize]
def __setitem__(self, idx, val):
assert len(val) == self.chunksize
bidx, mmap = self._mm_from_idx(idx)
mmap[bidx:bidx+self.chunksize] = val
def __len__(self):
assert not sum(self.sizes)%self.chunksize
return sum(self.sizes)/self.chunksize
def bubble_sort(self):
for i in xrange(0, len(self) - 1):
swap_test = False
for j in range(0, len(self) - i - 1):
if self[j] > self[j + 1]:
self[j], self[j + 1] = self[j + 1], self[j] # swap
swap_test = True
if swap_test == False:
break
self.flush()
def flush(self):
for mm in self.mmaps:
mm.flush()
def close(self):
self.flush()
for mm in self.mmaps:
mm.close()
for f in self.files:
f.close()
答案 0 :(得分:1)
列表的排序方法是用C语言编写的(在CPython中),因此根本不需要使用__getitem__
和_ _setitem__
方法。如果它确实使用了这些方法,那么它会大大减慢正常的list.sort()
您可以将文件索引存储在列表中,并使用list的内置排序和key
函数为您完成一些工作
答案 1 :(得分:1)
这里提供了实际的列表排序代码(第2000行):https://github.com/python-git/python/blob/master/Objects/listobject.c
据我所知,不可能将该代码用于不同的存储机制。
您可以更快地使用排序算法(使用快速排序等)或使用ctypes模块与基于C的排序算法(例如http://tomoyo.sourceforge.jp/cgi-bin/lxr/source/lib/sort.c)进行交互。
最后,您可以使用linux排序应用程序对数据进行排序(如果您希望在Python中控制它,则使用子进程模块)。 sort filea fileb filec
可能比你在Python,mmap或者不能做的任何事情都要快。
答案 2 :(得分:1)
你误解了从list
继承的内容。
您的Memwrap
不只是让list
界面 一个列表(这是一个内存结构,就像一个Python对象数组不能直接用Python表示)。然后添加一些额外的实例成员,并覆盖一些list
方法与您的成员交谈而不是正常的list
实例数据(因为您实际上从未调用基类实现)。请注意,Memwrap
仍然具有从list
继承的实例数据,但就数据而言,它仍然是一个空列表,其中添加了一堆属性。
内置类型的许多操作都是在C中实现的,只是直接使用C级数据而不是通过Python级钩子(如__getitem__
)。因此,虽然这种继承到get-the-interface的接口可以用于Python级别的类(虽然它确实是一个hack),但它通常不适用于内置类型。这肯定不是你对“构建类型”的子类化“应该”做的事情;更期望你使list
的工作方式略有不同(你可以添加默认值,额外方法,元数据等),而不是你做一个完全不同的共享接口的东西。为此,请参阅collections
模块中的ABC。
我没有看到如何在没有list
的情况下使用list
的内置排序。内存映射文件应该比执行大量的操作系统级别的调用更快,但是为了排序你实际上是在读取并重写所有文件的全部内容,所以我看不出你是如何得到它的比这更快;将所有文件读入内存,对其进行排序,然后将结果写入文件。
使用mmaps执行包含固定大小数据块的就地排序文件的技巧非常聪明,但是你必须一直使用C来实际让它工作并且速度很快。 Python没有针对inplace文件排序的操作(这是一个非常模糊的操作,因为除非你假设数据块是固定大小的,否则它是不可能的),你不能得到list
的排序它适合你,并且在Python中自己实现这样的排序肯定比一个好的C实现慢。也就是说,它应该是一个IO绑定操作,而不是计算绑定,所以你确定实际上可以比冒泡排序更快地完成 的工作吗?