Задать вопрос
@artinnok
бекенд-программист

Как увеличить быстродействие данного скрипта?

Скрипт:
from sys import argv
from math import cos, sin, pi, fmod, fabs, ceil
from tkinter import Canvas, Tk, mainloop
from decimal import *
from time import time

getcontext().prec = 5

start = time()
class Turtle:
    def __init__(self, x=250, y=0, angle=0):
        self.x = Decimal(x)
        self.y = Decimal(y)
        self.angle = Decimal(angle)
        self.angle_incr = Decimal(pi/6)
        self.step = Decimal(20)
        self.old_x = Decimal(x)
        self.old_y = Decimal(y)
        self.stack_x = []
        self.stack_y = []
        self.stack_angle = []

    def plus_angle(self):
        self.angle += self.angle_incr

    def minus_angle(self):
        self.angle -= self.angle_incr

    def get_nextx(self):
        if self.get_quarter() == 1:
            x = self.x - self.step*Decimal(fabs(sin(self.angle)))
        elif self.get_quarter() == 2:
            x = self.x - self.step*Decimal(fabs(sin(self.angle)))
        elif self.get_quarter() == 3:
            x = self.x + self.step*Decimal(fabs(sin(self.angle)))
        elif self.get_quarter() == 4:
            x = self.x + self.step*Decimal(fabs(sin(self.angle)))
        return x


    def get_nexty(self):
        if self.get_quarter() == 1:
            y = self.y + self.step*Decimal(fabs(cos(self.angle)))
        elif self.get_quarter() == 2:
            y = self.y - self.step*Decimal(fabs(cos(self.angle)))
        elif self.get_quarter() == 3:
            y = self.y - self.step*Decimal(fabs(cos(self.angle)))
        elif self.get_quarter() == 4:
            y = self.y + self.step*Decimal(fabs(cos(self.angle)))
        return y

    def F(self):
        self.old_x = self.x
        self.old_y = self.y
        self.x = self.get_nextx()
        self.y = self.get_nexty()

    def open_branch(self):
        self.stack_x.append(self.x)
        self.stack_y.append(self.y)
        self.stack_angle.append(self.angle)

    def close_branch(self):
        last = len(self.stack_x) - 1
        self.x = Decimal(self.stack_x.pop(last))
        self.y = Decimal(self.stack_y.pop(last))
        self.angle = Decimal(self.stack_angle.pop(last))

    def get_quarter(self):
        angle = fmod(self.angle, 2*pi)
        if angle < 0:
            angle += 2*pi
        if (0 <= angle) and (angle < pi/2):
            return 1
        elif (pi/2 <= angle) and (angle < pi):
            return 2
        elif (pi <= angle) and (angle < 3*pi/2):
            return 3
        elif (3*pi/2 <= angle) and (angle <= 2*pi):
            return 4

turtle = Turtle()
text = argv[1]
count = int(argv[2])

tk = Tk()
canv = Canvas(tk, width=500, height=500)


for i in range(count-1):
    print(text)
    data = text
    text = text.replace('F', data)

for item in text:
    if item == 'F':
        turtle.F()
        print(turtle.old_x, turtle.old_y, turtle.x, turtle.y)
        canv.create_line(turtle.old_x, turtle.old_y, turtle.x, turtle.y)
    elif item == '-':
        turtle.minus_angle()
    elif item == '+':
        turtle.plus_angle()
    elif item == '[':
        turtle.open_branch()
    elif item == ']':
        turtle.close_branch()

canv.pack()
finish = time()
print((finish-start)/60)
mainloop()


Версия Python - 3.4.3
Запускается из под командной строки таким образом:
python script.py F[-F][+F] N
где N - количество итераций
Скрипт нормально работает при N 1-4, но при N = 5 он неприемлемо долго вычисляет и не строит рисунок.
Как оптимизировать его?

P.S. Я постарался использовать Decimal, чтобы вычисления происходили с заданной точностью (избыточная точность нам не нужна, ибо это уменьшает производительность)
  • Вопрос задан
  • 254 просмотра
Подписаться 4 Оценить Комментировать
Помогут разобраться в теме Все курсы
  • Нетология
    Python-разработчик: расширенный курс + нейросети
    12 месяцев
    Далее
  • Яндекс Практикум
    Python-разработчик
    10 месяцев
    Далее
  • Skillbox
    Профессия Python-разработчик + ИИ
    10 месяцев
    Далее
Решения вопроса 1
@CobaltTheTerrible
Копипастю код на Python
Оптимизировать это не получится.

Ваша L-система содержит такой production rule, что при N=5 строка с инструкцией состоит из 172186881 символов. Подозреваю, что у вас даже эмулятор терминала вылетает, потому что это 160 мегабайт, которые скрипт выводит в терминал.

Для сравнения при N=4 строка с инструкцией содержит 26241 символ. Насколько я вижу у вас код, который делает рисунок, имеет линейную сложность. Т.е. даже если для N=4 выполнение программы занимает 1 секунду, то для N=5 по оптимистичной оценке (линейная сложность без большой константы впереди) потребуется 6562 секунды.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
ITK academy Краснодар
от 220 000 до 300 000 ₽
ITK academy Краснодар
от 75 000 ₽
DimaTech Ltd Краснодар
от 140 000 до 140 000 ₽