Python线程-内存不足

Python线程-内存不足,python,optimization,python-multithreading,Python,Optimization,Python Multithreading,我目前正在用python解决一个问题,以确定在安排交付时要采取的最佳路线。对我的代码的高级理解是,我读入所有建筑物(输入中“:”之前的值),然后计算到这些建筑物的所有可能路线。然后,我将生成的每个组合的计算拆分为一个线程,并返回返回“家”建筑的总时间(在所有情况下都是建筑“abc”) 我下面的代码在较小的数据子集(总共4栋建筑)上运行良好,但当我将代码扩展到13栋建筑(所需数量)时。在执行过程中,我遇到了内存错误 我有点纠结于如何解决这个问题,我从来没有遇到过一个问题,它会以指数级的速度爆炸。我

我目前正在用python解决一个问题,以确定在安排交付时要采取的最佳路线。对我的代码的高级理解是,我读入所有建筑物(输入中“:”之前的值),然后计算到这些建筑物的所有可能路线。然后,我将生成的每个组合的计算拆分为一个线程,并返回返回“家”建筑的总时间(在所有情况下都是建筑“abc”)

我下面的代码在较小的数据子集(总共4栋建筑)上运行良好,但当我将代码扩展到13栋建筑(所需数量)时。在执行过程中,我遇到了
内存错误

我有点纠结于如何解决这个问题,我从来没有遇到过一个问题,它会以指数级的速度爆炸。我的解决方案必须包括线程。如有任何建议/提示,将不胜感激

Input.txt(小子集):

Input.txt(完整数据):

当前代码:

import time
import os
import threading
import sys
from itertools import permutations
from functools import reduce


inputFile = 'Input.txt'
outputFile = 'output2.txt'

f=open(inputFile,'r')
line=f.readline()
buildings=[]
timings=[]
results={}

def run_me(TimeMatrix,combination,results,buildingDict):
    my_lock.acquire()
    results[' '.join(map(str, combination))] = GenerateTiming(TimeMatrix,combination,buildingDict)
    my_lock.release()

def GenerateTiming(TimeMatrix,combination,buildingDict):
    current=combination
    mySum=[]
    for i in range(len(current)-1):
        currentBuilding=buildingDict[current[i]]
        nextBuilding=buildingDict[current[i+1]]
        mySum.append(TimeMatrix[currentBuilding-1][nextBuilding])
    result=sum(mySum)
    return(result)


while line: 
    b=line.split(":")[0]
    t=line.split(":")[1]
    b=b.strip()
    t=t.strip()
    buildings.append(b)
    timings.append(t)
    home=buildings[0]
    line=f.readline()



combinations=[]
first, *rest = buildings
for p in permutations(rest):
    combinations.append([first,*p,first])

bldLKP=combinations[0]
buildingDict={}

for i in range(1,len(bldLKP)):
    buildingDict[bldLKP[i-1]] = i
    i=i+1


TimeMatrix=[[i] + [int(n) for n in s.split()] for i, s in enumerate(timings, 1)]

#Threading Section
my_lock=threading.Lock()
my_threads=list()


for comb in combinations:
    my_threads.append(threading.Thread(target=run_me,args=(TimeMatrix,comb,results,buildingDict)))

for current_thread in my_threads:
    current_thread.start()

for current_thread in my_threads:
    current_thread.join()


lowest=min(results.values())
final=[key for key in results if results[key]==lowest]

print(' '.join(map(str, final)),lowest)


编辑:我应该提到的是,我相信问题出现在以下代码中,我正在识别所有可能的建筑物组合。然而,我不知道我如何才能做到这一点,因为每一条路径都需要检查最快的路线

combinations=[]
first, *rest = buildings
for p in permutations(rest):
    combinations.append([first,*p,first])

在代码中,您创建排列,然后运行线程来计算每个路由的总和(时间)。代码运行的线程数

小子集(4栋建筑)

您为其余建筑(不包括第一个)创建排列,因此数量将为(4-1)!=3*2*1=6

完整数据(13栋建筑) (13-1)! = 479001600(应创建此数量的螺纹

我建议不要在这种情况下使用线程

我写了一个简单的递归函数来实现你所需要的。我对置换有很大的性能改进。如果当前时间大于最小时间,它不会更深入。请看一下我的实现

import threading

time_matrix = {}
buildings = []

with open('input.txt', 'r') as f:
    lines = []
    for row in f.readlines():
        building, line = row.split(':')
        building = building.strip()
        buildings.append(building)
        lines.append(line.strip())
        time_matrix[building] = {}

for building, line in zip(buildings, lines):
    for index, time_to_reach in enumerate(line.split(' ')):
        to_building = buildings[index]
        time_matrix[building][to_building] = int(time_to_reach)

first, *rest = buildings


results = []
class MyThread(threading.Thread):

    def __init__(self, time_matrix, current_building, to_visit_buildings, current_path, current_time):
        super().__init__()
        self.time_matrix = time_matrix
        self.current_building = current_building
        self.to_visit_buildings = to_visit_buildings
        self.current_path = current_path
        self.current_time = current_time

    def run(self):
        min_time, min_paths = self.calculate(self.time_matrix, self.current_building, self.to_visit_buildings, self.current_path, self.current_time)
        if min_paths and min_time:
            results.append((min_time, min_paths))

    def calculate(self, time_matrix, current_building, to_visit_buildings, current_path, current_time, min_time=None, min_paths=None):

        if min_paths and min_time < current_time:
            return None, None

        if not to_visit_buildings:
            current_time += time_matrix[current_building][first]
            if min_time is None or min_time > current_time:
                path = [first, *current_path, first]
                if min_time == current_time:
                    return current_time, min_paths + [path]
                else:
                    return current_time, [path]

        for building in to_visit_buildings:
            new_to_visit_buildings = [b for b in to_visit_buildings if b != building]
            new_current_path = [*current_path, building]
            new_current_time = current_time + time_matrix[current_building][building]
            new_min_time, new_min_paths = self.calculate(time_matrix, building, new_to_visit_buildings, new_current_path, new_current_time, min_time, min_paths)
            if new_min_paths and new_min_time and (not min_time or new_min_time < min_time):
                min_time = new_min_time
                min_paths = new_min_paths

        return min_time, min_paths

my_threads = []
for building in rest:
    to_visit = [b for b in rest if b != building]
    current_time = time_matrix[first][building]
    my_threads.append(MyThread(time_matrix, building, to_visit, [building], current_time))

for current_thread in my_threads:
    current_thread.start()

for current_thread in my_threads:
    current_thread.join()

min_paths, min_time = min(results, key=lambda r: r[0])

print(min_paths, min_time)
导入线程
时间矩阵={}
建筑物=[]
以open('input.txt','r')作为f:
行=[]
对于f.readlines()中的行:
建筑,行=行。拆分(“:”)
building=building.strip()
建筑物。附加(建筑物)
lines.append(line.strip())
时间矩阵[建筑]={}
对于建筑,zip中的线(建筑,线):
对于索引,枚举中到达的时间(第行拆分(“”)):
to_building=建筑物[索引]
时间矩阵[建筑][到建筑]=int(到达时间)
首先,*休息=建筑物
结果=[]
类MyThread(threading.Thread):
定义初始时间(自我、时间矩阵、当前建筑、访问建筑、当前路径、当前时间):
super()。\uuuu init\uuuuu()
self.time\u矩阵=time\u矩阵
self.current_building=当前_building
self.to_visit_buildings=to_visit_buildings
self.current\u path=当前路径
self.current\u time=当前时间
def运行(自):
最小时间,最小路径=self.calculate(self.time\u矩阵,self.current\u建筑,self.to\u访问\u建筑,self.current\u路径,self.current\u时间)
如果最小路径和最小时间:
结果.追加((最小时间,最小路径))
def计算(自我、时间矩阵、当前建筑、访问建筑、当前路径、当前时间、最小时间=无、最小路径=无):
如果最小路径和最小时间<当前时间:
返回None,None
如果不去参观,请参观:
当前时间+=时间矩阵[当前建筑][第一]
如果最小时间为无或最小时间>当前时间:
路径=[第一条,*当前路径,第一条]
如果最小时间==当前时间:
返回当前路径时间,最小路径+[路径]
其他:
返回当前时间[路径]
要在to_中进行建筑,请访问_建筑:
新的访问大楼=[b代表b访问大楼,如果b!=大楼]
新建当前路径=[*当前路径,建筑]
新建当前时间=当前时间+时间矩阵[当前建筑][建筑]
新建\最小\时间,新建\最小\路径=自。计算(时间矩阵,建筑,新建\到\参观\建筑,新建\当前\路径,新建\当前\时间,最小\时间,最小\路径)
如果新的最小路径和新的最小时间和(不是最小时间或新的最小时间<最小时间):
最小时间=新的最小时间
最小路径=新的最小路径
返回最小时间,最小路径
我的线程=[]
对于静止建筑:
to_visit=[b为b,如果b为b,则b为b!=建筑]
当前时间=时间矩阵[第一个][建筑]
my_threads.append(MyThread(时间矩阵,建筑,访问,[建筑],当前时间))
对于my_线程中的当前_线程:
当前线程。开始()
对于my_线程中的当前_线程:
当前线程。join()
最小路径,最小时间=min(结果,键=lambda r:r[0])
打印(最小路径、最小时间)
对于完整的数据输出:
['abc',yza',bcd',ghi',jkl',efg',stu',hij',vwx',def',pqr',mno',klm',abc']20

你应该看看这个网站:“最直接的解决方案是尝试所有排列(有序组合),看看哪一种排列最便宜(使用蛮力搜索)。这种方法的运行时间在多项式因子O(n!)内,这是城市数量的阶乘,因此,即使只有20个城市,此解决方案也不切实际。”为什么使用线程而不是多线程处理?@AMC我编辑了我的原始问题。我的解决方案需要使用线程。哦,这是一个奇怪的限制,不是吗?不幸的是,我需要将线程作为解决方案的一部分使用。在这种情况下,您需要创建例如20个线程并分散负载。请再次检查代码。我将其更新为使用多线程。但是它不会提高性能如果我需要考虑捆绑的路径,并以相同的距离打印所有路径,我应该如何修改上述代码?我尝试使用计算函数,但每次只得到1个答案。
combinations=[]
first, *rest = buildings
for p in permutations(rest):
    combinations.append([first,*p,first])
import threading

time_matrix = {}
buildings = []

with open('input.txt', 'r') as f:
    lines = []
    for row in f.readlines():
        building, line = row.split(':')
        building = building.strip()
        buildings.append(building)
        lines.append(line.strip())
        time_matrix[building] = {}

for building, line in zip(buildings, lines):
    for index, time_to_reach in enumerate(line.split(' ')):
        to_building = buildings[index]
        time_matrix[building][to_building] = int(time_to_reach)

first, *rest = buildings


results = []
class MyThread(threading.Thread):

    def __init__(self, time_matrix, current_building, to_visit_buildings, current_path, current_time):
        super().__init__()
        self.time_matrix = time_matrix
        self.current_building = current_building
        self.to_visit_buildings = to_visit_buildings
        self.current_path = current_path
        self.current_time = current_time

    def run(self):
        min_time, min_paths = self.calculate(self.time_matrix, self.current_building, self.to_visit_buildings, self.current_path, self.current_time)
        if min_paths and min_time:
            results.append((min_time, min_paths))

    def calculate(self, time_matrix, current_building, to_visit_buildings, current_path, current_time, min_time=None, min_paths=None):

        if min_paths and min_time < current_time:
            return None, None

        if not to_visit_buildings:
            current_time += time_matrix[current_building][first]
            if min_time is None or min_time > current_time:
                path = [first, *current_path, first]
                if min_time == current_time:
                    return current_time, min_paths + [path]
                else:
                    return current_time, [path]

        for building in to_visit_buildings:
            new_to_visit_buildings = [b for b in to_visit_buildings if b != building]
            new_current_path = [*current_path, building]
            new_current_time = current_time + time_matrix[current_building][building]
            new_min_time, new_min_paths = self.calculate(time_matrix, building, new_to_visit_buildings, new_current_path, new_current_time, min_time, min_paths)
            if new_min_paths and new_min_time and (not min_time or new_min_time < min_time):
                min_time = new_min_time
                min_paths = new_min_paths

        return min_time, min_paths

my_threads = []
for building in rest:
    to_visit = [b for b in rest if b != building]
    current_time = time_matrix[first][building]
    my_threads.append(MyThread(time_matrix, building, to_visit, [building], current_time))

for current_thread in my_threads:
    current_thread.start()

for current_thread in my_threads:
    current_thread.join()

min_paths, min_time = min(results, key=lambda r: r[0])

print(min_paths, min_time)