воскресенье, 22 июля 2018 г.

Ускоряем Python через cython


Python в настоящее время стал довольно популярным и универсальным языком. Во много благодаря своему удобному синтаксису, огромному количеству библиотек и простой расширяемости сишными модулями. Конечно когда говорят о скорости, все дружно морщат нос. Однако, в приложениях из реальной жизни, при привальном подходе, вы скорее упретесь в базу или сеть, чем в Python. Конечно есть всякие интересные вычисления, где интерпретатор дает большие накладные расходы и Gil не сильно радует, нет типов для возможных оптимизаций и упрощенного отлова ошибок. Все так, но не совсем. 

В python есть такая вещь как Type Hints. Мы просто можем указать типы данных для передаваемых значений в функции, а также типы возвращаемых значений.

def greeting(name: str) -> str:
    return 'Hello ' + name
Конечно, для интерпретатора, это мало, что значит. Основная идея была в улучшении подсказок в средах разработки, упрощенного анализа кода и поиска багов, может помочь вам писать код строже (потому что вы начнете соблюдать типы и думать о структуре кода, а не пихать все в одну переменную, если вы конечно так делали), так же это может помочь статическим анализаторам кода в нахождении проблем. Штука интересная, но не сильно помогающая в продакшене. Но на самом деле, теперь мы можем сделать очень интересные вещи для ускорения кода. И нам поможет Cython. В детали не будем залазить, возьмем простой пример показывающий общую суть.

def fun(x: float) -> float:
    return x*x-x

def integrate_f(a: float, b: float, N: int):
    s : float = 0
    dx : float = (b - a) / N
    for i in range(N):
        s += fun(a + i * dx)
    return s * dx
Вот пример нашего кода на питоне (прямо из документации). Проверяем:

begin = time.time()
print(tpy.integrate_f(1006, 2610, 100000000))
print(time.time() - begin)

Итог:
5584257516.163277
25.64701795578003

25 секунд, не очень радостное время. Однако, если мы переименуем файл в pyx и дополним тремя декораторами:

import cython

@cython.cfunc  # cdef functions are faster but not callable from python
def fun(x: float) -> float:
    return x*x-x

@cython.locals(i=cython.int, N=cython.int)  # better integration soon
@cython.cdivision(True)  # remove divide by zero protection
def integrate_f(a: float, b: float, N: int):
    s : float = 0
    dx : float = (b - a) / N
    for i in range(N):
        s += fun(a + i * dx)
    return s * dx

Как это добро компилировать смотрим в документации. Проверяем: 

import t (наш cython модуль)
import time

if __name__ == '__main__':
    begin = time.time()
    print(t.integrate_f(1006, 2610, 100000000))
    print(time.time() - begin)

Итог:
5584257516.166599
0.15540504455566406

Результат более, чем впечатляет. Затраченных усилий минимум и увеличение в поддержке кода не значительное. Конечно чем сложнее куски, тем сложнее будет соблюдать типизацию, некоторые вещи могут вообще не дать видимого прироста. Однако, если вы уперлись в Python, то можно попробовать использовать Cython для получения профита. В каждой конкретной задаче нужно смотреть оправданность усилий и полученного результата, но в целом профит может быть велик.

Для сравнения делаем в лоб одинаковое решение на go:

package main

import (
    "log"
    "time"
)

func fun(x float32) float32 {
    return x*x - x
}

func integrate_f(a float32, b float32, N int) float32 {
    s := float32(0.0)
    dx := (b - a) / float32(N)
    for i := 0; i < N; i++ {
        s += fun(a + float32(i)*dx)
    }
    return s * dx
}

func main() {
    start := time.Now()
    integrate_f(1006, 2610, 100000000)
    elapsed := time.Since(start)
    log.Printf("time %s", elapsed)
}


Получим 0,105165. В данном случаи выгрыш от cython не значителен. Я это к тому, что в каждой задаче хорошо свое решение и пытаться переписать все на go не решение всех проблем.

вторник, 26 января 2016 г.

Ставим Go на linux с официального сайта

Что-бы иметь самую новую версию языка, лучше ставить ее с официального сайта, а не из репозиториев вашего дистрибутива.

Качаем нужную версию:

wget https://storage.googleapis.com/golang/...

Распаковываем:

sudo tar -xzf goVersion.linux-xxx.tar.gz -C /usr/local

Прописываем пути к Go и папке проектов:

sudo vi /etc/profile
export PATH=$PATH:/usr/local/go/bin
export GOPATH="$HOME/workspace

четверг, 23 октября 2014 г.

quicksort на python

Описание алгоритма.

def quicksort(array):
    if len(array) <= 1:
        return arr
    else:
        return quicksort([x for x in array[1:] if x < array[0]]) + [array[0]] + quicksort([x for x in array[1:] if x >= array[0]])

вторник, 7 октября 2014 г.

алгоритм Евклида на python

Алгори́тм Евкли́да — эффективный алгоритм для нахождения наибольшего общего делителя двух целых чисел.

Подробнее об алгоритме читаем на википедии.

Пример реализации на python:

def evc(a, b):
    if a < b:
        a, b = b, a
    r = 1
    while r > 0:
        r = a % b
        a = b
        b = r

    return a

понедельник, 29 сентября 2014 г.

Запускаем android studion на ubuntu 14.04

При попытке запуска приложения на своём девайсе через android studio получил сообщение об ошиьке "ADB Not Responding ...".

Лечится просто:

sudo apt-get install lib32z1 lib32z1-dev lib32stdc++6

пятница, 28 марта 2014 г.

Оценка качества архитектуры проекта

Очень часто встречаю споры по поводу оценки качества архитектуры проекта. Видел много разных сложных метрик и громких заявлений. Моё мнение, что большинство вводит эти метрики для начальства или чтобы похвастаться перед другими. Я считаю, что нас должно интересовать 3 вещи:

  1. соответствует ли программа требованиям (т.е. выполняет все функции прописанные в техническом задании в полной мере);
  2. насколько легко лично для вас/вашей команды происходит процесс внесения изменений в систему;
  3. легко ли вы можете подключить нового разработчкика к работе над проектом.
Наверное можно придумать ещё метрики, но эти основные и без них никуда. Если ответы - да, легко, легко, то мне кажется что вы поработали над архитектурой должным образом. Если же нет, то вам есть куда расти.

вторник, 11 марта 2014 г.

Dragon Age: Origins

Да-да я знаю, что игра стара и что есть уже вторая часть и скоро вроде бы будет третья. В своё время я начал играть как раз со второй части, но не смог продержаться больше часа. Я понимаю, что игра вполне себе стоящая но не зацепило. Поэтому первую часть я даже ставить не стал и как оказалось зря. То-ли настрой у меня был на игры лучше, то-ли ещё какие-то причины но мне очень понравилась игра Dragon Age: Origins.

Хвалить игру со средними оценками 8.5 из 10 конечно не сложно. Однако у меня остались не совсем однозначные впечатления от игры. Главный и вообщем-то единственный минус для меня - это боевка. Честно говоря мне понравился сюжет, персонажи и хотелось узнать, что там дальше. Но приходилось довольно много драться, что логично. Но как же меня напрягали эти моменты. Неудобная камера, слабый интеллект союзников, длинные и затянутые подземелья. Тут конечно во многом моя вина, я понимаю что там можно выставить как вести себя своим спутникам, но всё равно это спасает не особо. В итоге я так и не смог нормально играть магом, хотя все рпг прохожу магами, где есть такая возможность. Проходил всю игру в три воина включая меня и лекаря. Не знаю, что у меня с руками но все остальные связки были нерабочими у меня. Вообщем боевки мне не понравились, но наверное если заморочиться и разобраться можно настроить всё хорошо. Но у меня честно говоря не было времени и желания разбираться как управлять ещё 3 персонажами, я бы и один побегал или бы уже пусть они сами вели себя адекватно. Финальный бой в итоге меня бесил по страшному, переключался между героями как угорелый, чтобы эти дебилы не дохли и в основном играл за лечащего мага, который сам лечит как то уж совсем криво.

Всё остальное же мне очень понравилось, не плохо проработанные персонажи. Интересный сюжет, да вообщем-то почти без сюрпризов, но интересно. Во общем ради этого я и играл и терпел долгие сражения с ордами нечисти. И главное для меня, что игра зацепила настолько, что прошёл её не смотря на нехватку времени.

Соглашусь со всеми оценками, но лично меня выбесило управление ужасно, поэтому не поленитесь в начале игры почитать как правильно управлять отрядом, чтобы получать удовольствие от игры.