Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用全局变量在python中加速Levenshtein距离计算_Python_Performance_Variables_Global - Fatal编程技术网

使用全局变量在python中加速Levenshtein距离计算

使用全局变量在python中加速Levenshtein距离计算,python,performance,variables,global,Python,Performance,Variables,Global,嗨,我正在使用python进行生物信息学的一个项目 我有一个函数,它使用Needleman-Wunsch算法计算查询和下一代测序平台读取之间的编辑距离。(两个字符串都带有字母:“ACGT”) 我的脚本运行得很好,但运行时间很长,因为函数的调用次数总计超过1亿次。 在函数中,我使用一个大小为MxN的二维列表,其中M是查询的长度,N是读取的长度。 每次调用函数时,必须在内存中重新创建此2D列表,然后才能使用计算填充它。我想知道是否可以通过创建一个2D列表作为全局变量,然后将该列表的句柄作为参数传递给

嗨,我正在使用python进行生物信息学的一个项目

我有一个函数,它使用Needleman-Wunsch算法计算查询和下一代测序平台读取之间的编辑距离。(两个字符串都带有字母:“ACGT”) 我的脚本运行得很好,但运行时间很长,因为函数的调用次数总计超过1亿次。 在函数中,我使用一个大小为MxN的二维列表,其中M是查询的长度,N是读取的长度。 每次调用函数时,必须在内存中重新创建此2D列表,然后才能使用计算填充它。我想知道是否可以通过创建一个2D列表作为全局变量,然后将该列表的句柄作为参数传递给函数来加快这个过程。这样,操作系统只需分配一次内存。 希望我把问题说清楚。 从操作系统请求内存以获取列表需要多长时间。这有意义吗

编辑: 根据要求提供一些示例代码:

该函数遍历二维数组并用数字填充:

import time
import random

def do_stuff():
    row = 12
    col = 12
    newlist = [[0 for _ in range(row)] for _ in range(col)]

    myrand = random.choice(range(100))

    for i in range(col):
        for j in range(row):
            newlist[i][j] = myrand

time1 = time.time()

for _ in range(1000000):
    do_stuff()

print(f'This took {time.time()-time1} seconds')
这段代码在我的笔记本电脑上运行大约22秒

import time
import random

row = 12
col = 12
newlist = [[0 for _ in range(row)] for _ in range(col)]

def do_stuff():
    myrand = random.choice(range(100))

    for i in range(col):
        for j in range(row):
            newlist[i][j] = myrand

time1 = time.time()

for _ in range(1000000):
    do_stuff()

print(f'This took {time.time()-time1} seconds')
更改代码时,二维列表只创建一次,只需约14秒

当然,实际函数在将数字插入列表之前会进行一些计算。如果您想要完整的功能,请告诉我,但我认为这可能会更快

编辑2:

所以在阅读了你所有的评论之后,我认为最好的方法是使用一个类。我在一个类中测试了上面的代码:

class myclass:
    def __init__(self):
        self.row = 12
        self.col = 12
        self.newlist = [[0 for _ in range(self.row)] for _ in range(self.col)]

    def do_stuff(self):
        myrand = random.choice(range(100))

        for i in range(self.col):
            for j in range(self.row):
                self.newlist[i][j] = myrand

time1 = time.time()

myinstance = myclass()

for _ in range(1000000):
    myinstance.do_stuff()

print(f'This took {time.time()-time1} seconds')
这不再像上面的第一个例子那么快了,现在大约需要17秒

这是与重新创建列表的比较:

class myclass:
    def __init__(self):
        pass

    def do_stuff(self):
        row = 12
        col = 12
        newlist = [[0 for _ in range(row)] for _ in range(col)]

        myrand = random.choice(range(100))

        for i in range(col):
            for j in range(row):
                newlist[i][j] = myrand


time1 = time.time()

myinstance = myclass()

for _ in range(1000000):
    myinstance.do_stuff()

print(f'This took {time.time()-time1} seconds')
现在大约需要22秒

所以我想我现在要用第一类的例子。你能确认我以正确的方式声明了变量吗?现在比以前长了3秒(上面的第一个示例是14秒),这只是因为使用了一个类,还是我把变量搞砸了?
谢谢。

这是我对性能影响的看法,将列表包含在函数中的本地部分,而不是“全局”


编辑:正如@DanD在评论中指出的那样,我在使用更传统的堆栈和堆之前写过(并删除了)。对于Python来说,这并不完全正确。Python虚拟机(PVM)只使用私有堆来分配其对象。但是PVM本身已经实现为一个堆栈。然后Python使用引用计数器(除其他外)跟踪对象,不管它们是否应该被丢弃。 当您使用第一个示例时,列表对象一次又一次地被推到堆栈上。前一个列表对象的引用计数器减少,然后在引用计数器达到0时删除。这是一个很大的开销。 第二个示例创建一次list对象,使引用计数器满足要求,然后PVM可以在每次调用时使用该对象

因此:不是为每个调用重新创建列表对象并生成新引用,而是通过仅使用相同引用创建1个列表对象来获得性能

下面是一个小示例,简而言之,这是您的第一个和第二个示例:

# Creating a list of lists. Notice the reference ID's
>>> z = ([], [], [])
>>> id(z), [id(i) for i in z]
(2319201223088, [2319201319560, 2319201317128, 2319201318280])

# Overwriting the z variable with a new list of lists. Notice the reference ID's changes
>>> z = ([], [], [])
>>> id(z), [id(i) for i in z]
(2319201201752, [2319201354120, 2319201320776, 2319201318216])

# This is just to show, that the reference ID's are preserved, if you use the second example
>>> z = list(z)
>>> id(z), [id(i) for i in z]
(2319201357704, [2319201354120, 2319201320776, 2319201318216])

对于您最初的问题:操作系统在检索内存分配方面很快,但在您的情况下很难准确确定,因为PVM有两个内存处理程序:一个。但这不是你在这件事上的主要问题

你也可以附上你的代码吗?请阅读解释,你可以只使用一个全局变量(在本例中为2D列表。您的函数可以访问该列表,而无需使用全局关键字或将其作为参数传递给函数。您必须将定义变量的模块导入到您的当前模块中,如本文所示。感谢您的快速回复。上面是示例代码。感谢您提供链接。这本书读得很好。我还没有使用过类或可变项,但我明天会进一步研究。我的测试表明,如果我不在每次函数正常运行时重新分配内存,代码可能会更快一些?Python不是这样工作的。这是对C的一个很好的描述。在Python中,所有内容都是堆分配的。savings完全来自于创建一次嵌套列表,而不是每次调用该函数。@DanD.我同意。PVM的实现是基于堆栈的,然后它们使用自己的“私有堆”,通过引用计数来管理对象。但其思想是“有点”同样。您使用的是指向列表的同一指针,它保持了引用计数器的位置。但我想我会将您的观点合并到答案中。非常感谢你们的详细答案,这非常有用。您可以使用类查看上面的新代码吗。