Pull to refresh
58
0
Alexander Kalinin @alec_kalinin

User

Send message
Если я понял правильно, то по идеологии «Julia» это тоже самое что и «Python + Numba», только язык более современный. Но стиль разработки научного кода не слишком то и различается. Мы сначала пишем прототип, а если нужна производительность расставляем типы, что позволяет выполнить эффективную JIT компиляцию.

Но вот тут то и кроется проблема для широкого применения языка. Если от Python сразу ожидают медленной скорости и знают приемы как ее преодолеть, то от Julia сразу ожидают высокой производительности. А это не всегда работает. Например вот в этой статье habr.com/ru/post/483864 реализация Python + Numba была в два раза быстрее реализации от Julia.

Таким образом мы имеем Python мир, в котором собрано уже все, что может быть в мире вычислений. Да и проблемы с производительностью уже в прошлом, по большому счету.

С другой стороны есть развивающийся мир Julia, в котором все вроде бы более красиво и чисто. Но… Автоматом все-равно быстро то не работает, нужно также думать как оптимизировать код. Да и библиотек маловато.

В результате под данным TIOBE Julia за 2019 год опустилась в рейтинге языков с #37 до #47 места, что грустно.
Выше уже ответили, нужны только numpy и numba:
$ pip3 install numpy
$ pip3 install numba


На всякий случай, вот полный код:
#!/usr/bin/env python3
import sys
import time
import numpy as np
from numba import jit


@jit
def lev_dist(s1: bytes, s2: bytes) -> int:
    m = len(s1)
    n = len(s2)

    # Edge cases.
    if m == 0:
        return n
    elif n == 0:
        return m

    v0 = np.arange(0, n + 1)
    v1 = np.arange(0, n + 1)

    for i, c1 in enumerate(s1):
        v1[0] = i + 1

        for j, c2 in enumerate(s2):
            subst_cost = v0[j] if c1 == c2 else (v0[j] + 1)
            del_cost = v0[j + 1] + 1
            ins_cost = v1[j] + 1

            # min(subst_cost, del_cost, ins_cost) is slow.
            min_cost = subst_cost if subst_cost < del_cost else del_cost
            if ins_cost < min_cost:
                min_cost = ins_cost
            v1[j + 1] = min_cost

        v0, v1 = v1, v0

    return v0[n]


if __name__ == "__main__":
    s1 = b"a" * 15_000
    s2 = s1
    s3 = b"b" * 15_000

    exec_time = -time.monotonic()

    print(lev_dist(s1, s2))
    print(lev_dist(s1, s3))

    exec_time += time.monotonic()
    print(f"Finished in {exec_time:.3f}s", file=sys.stderr)
Тут вопрос сложный. У нас есть Java Script с его V8, nim с его компиляцией в C, Julia с ее компиляцией через llvm. Да и тот же pypy в несколько раз медленнее numba, хотя оба пытаются компилировать код.

На мой взгляд вполне честно все сравнивать с точки зрения разработчика. Есть код, есть плафторма, есть результат.

Да и чем, грубо говоря, декоратор "@jit" так уж сильно отличается от набора специальных флагов «gcc» с подсказками для оптимизаций?
Можно привести и к 20 тыщ, но в целом видно, что C и Python практически сравнимы по скорости.
Ну и, кстати, сколько тогда работы выполняется в питоне, а сколько — в C?
Ну Python же это язык. У него может быть реализация как у интепретируемого языка, а может быть и jit компиляция.

А по факту я взял приведенный исходник на Python, практически добавил всего одну аннотацию, запустил в стандартной реализации CPython и получил практически скорость языка С. С точки зрения разработчика я нигде не вышел из окружения Python.
Про то, что Python не готов для вычислений, вы не правы. И PyPy не нужен, нужны только Numpy, Numba и самый обычный Python. Вот результаты

C
Windows 10, gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)
$ gcc ld.c -Ofast -fPIC -fPIE -static -flto -o ld.exe
$ ld.exe
0
15000
Finished in 0.934s

Python
Косметические изменения в коде:
import sys
import time
import numpy as np
from numba import jit


@jit
def lev_dist(s1: bytes, s2: bytes) -> int:
    m = len(s1)
    n = len(s2)

    # Edge cases.
    if m == 0:
        return n
    elif n == 0:
        return m

    v0 = np.arange(0, n + 1)
    v1 = np.arange(0, n + 1)

    for i, c1 in enumerate(s1):
        v1[0] = i + 1

        for j, c2 in enumerate(s2):
            subst_cost = v0[j] if c1 == c2 else (v0[j] + 1)
            del_cost = v0[j + 1] + 1
            ins_cost = v1[j] + 1

            # min(subst_cost, del_cost, ins_cost) is slow.
            min_cost = subst_cost if subst_cost < del_cost else del_cost
            if ins_cost < min_cost:
                min_cost = ins_cost
            v1[j + 1] = min_cost

        v0, v1 = v1, v0

    return v0[n]


Результаты на Windows 10, Python 3.7.5
$ python ld.py
0
15000
Finished in 0.968s

На долю процентов C быстрее, но скорости практически сравнимы.
Я вижу, что тут используется дистрибутив Anaconda. Большая часть таких ошибок лечится одной командой anaconda package manager:
$ conda install libgcc
Использовать то можно, конечно. Но дело не в гипотетической возможности использования, а в чистоте и продуктивности решения.

Python это «официальный» API для Tensorflow. По статистике на github.com/tensorflow/tensorflow Python составляет более 30% кодовой базы, что для совсем тонкого интерфейса многовато. Да и вообще использование low-level C/C++ модулей распространенное решение в экосистеме Python, это делается очень просто и органично. Python тут выступает очень эффективным «клеем» для интеграции low-level функций.

Для экосистемы Julia использование C/С++ модулей не слишком «спортивно». Julia позиционируется как язык, способный конкурировать с C/C++ на его поле за счет развитой системы типов с диспетчеризацией вызовов и JIT компиляции. Иделогия Julia как раз в том, чтобы иметь на высоком уровне выразительный язык типа MatLab для научных вычислений, но при этом иметь возможность получать произодительность нативной плафтормы. Поэтому оборачивание C/C++ TensorFlow в Julia выглядит как пренебрежение идеологией Julia.
Спасибо за ссылки! Да, это все интересные иницативы. Посмотрим, как оно все будет развиваться. В любом случае я рад, что область научных вычислений сейчас активно идет вперед.
Есть github.com/JuliaLang/PackageCompiler.jl
Можно сгенерировать запускаемый бинарник. Только код должен быть оформлен в пакет и быть установлен как пакет. А бинарник будет довольно жирным.
Да, я его как раз и пробовал. Но для меня пока и процесс компиляции, и результат оказались довольно тяжеловесными. Надеюсь, что компилятор будет постепенно совершенствоваться.
Нам удавалось избегать использования Питона где бы то ни было. И, как раз сейчас, я сомневаюсь в его будущем и целесообразности каких-либо инвестиций в него.
Хмм… Ну не знаю. Пока я наблюдаю как раз обратную картину взрывного роста использования Питона в научных расчетах. Почти каждая крупная компания недавно выдвинула свою инициативу развития Python. Вот некоторые примеры
— Intel: software.intel.com/distribution-for-python, полная интеграция со своими флагманскими библиотеками для высокопроизводительных расчетов Intel Math Kernel Library, Intel Data Analytics Acceleration Library
— NVidia: developer.nvidia.com/how-to-cuda-python, полная поддержка компиляции Python для GPU
— Google: это TensorFlow, сейчас один из важнейших продуктов для Google,
— Netflix: практически полностью построен на Python, medium.com/netflix-techblog/python-at-netflix-bba45dae649e, тут как раз и преимущество Python, что на нем можно писать не только научные расчеты, а строить всю инфраструктуру
— одно из главных открытий в физике последних лет, непосредственно измеренные гравитационные волны, были рассчитаны на Python: pycbc.org,
— много много других

Вот еще интересная публикация о статистике использования фреймворков для машинного обучения, собранная по данным упоминания на самых популярных научных конференциях: thegradient.pub/state-of-ml-frameworks-2019-pytorch-dominates-research-tensorflow-dominates-industry. Там говорится, что по большому счету остались только два самых популярных фреймворка: TensorFlow и PyTorch, оба это Python.
На счёт библиотек на каждый чих, большинство из них давно заброшены, имеют проблемы стабильности и совместимости с новыми версиями языка.
Вот это все-таки не так. Все хоть как-либо значимые библиотеки уже давно собраны в очень качественные дистрибутивы с полной поддержкой последних версий Python и регулярным обновлением под три платформы: Windows, Linux, Mac. Вот наиболее популярный пакет www.anaconda.com/distribution/#download-section. Мне сложно придумать типовую математическую задачу, которая не была бы уже в том или ином виде реализована в этом дистрибутиве.
Я уже несколько лет активно присматриваюсь к Julia. В основном я пытаюсь заменить Питон для научных расчетов на что-то другое. Но сейчас для меня будущее Julia все-таки под вопросом.

Julia для меня хороша тем, что из коробки предоставляет неплохой язык программирования для научных расчетов с почти идеальной производительностью. Но как язык общего уровня для других задач, например для веба или простых утилит, она проигрывала Питону.

Питон меня полностью устраивает как язык общего уровня. Крайне нравится идеология векторизованных вычислений через NumPy. Но еще пару лет тому назад меня расстраивали три вещи: а) не всегда можно все выразить через NumPy, да и сам NumPy местами медленный, b) GIL, и сложность с параллельными вычислениями и c) отсутствие типизации, что важно для сложных проектов. Все эти проблемы решались через Cython, но код при этом становился крайне плохо читаемым.

Но за последние несколько лет Python практически решил все эти проблемы: a) появилась Numba, JIT компиляция на лету; теперь достаточно всего пары аннотаций для максимально производительного параллельного кода, b) в python 3.8 появилась концепция субинтерпретаторов с экспериментальным API для shared memory, т.е. проблемы GIL уже почти нет и c) очень неплохая система аннотации типов.

В настощий момент я на чистом Python (Numpy + Numba) могу написать красивый код (с ясной аннотацией типов), который по производительности не будет уступать Julia. При этом у меня есть широчайшее коммьютнити и библиотеки на каждый чих.

Но вообще, я очень болею за Julia! Это важный проект для всей области научных расчетов. Мне очень не хватает в Julia простой компиляции в нативный код. Было бы это просто (например, как в nim с его проектом nimpy), я пробовал бы потихоньку на julia писать бинарные модули и использовать из Python.
Для простоты пусть все числа будут разными.
О! Спасибо за ссылку. Просто он был недоступен у меня пару часов назад. Может что-то у меня не так было.
Да, вы правы. Это весь цикл можно заменить на такой код:
let out = intervals.map(o => o.toString(arr)).join(',');

Тут все хорошо. Но на мой взгляд эта строчка по стилю слегка не бьется с циклом выше. А я хотел написать максимально простой однообразный код.
Да, массив должен быть отсортирован, cейчас добавлю. Спасибо за уточнение!
Идея то как раз в том, чтобы написать такую функцию карандашом на бумажке на собеседовании без всяких гуглов.
Огромное спасибо за проект! Собрал проект из репозитория, вернулся в детство.

Собрал под Windows 10, Visual Studio Community 2019. Единственно, в файле Board.cpp в строчке 169 добавил проверку:
bool CMotherboard::IsFloppyEngineOn() const
{
	if (m_pFloppyCtl == NULL)
		return false;

	return m_pFloppyCtl->IsEngineOn();
}
Очень рад слышать, что сообщество БК 0010 живо и активно! С БК 0010 начался мой путь в ИТ. Помню как я ребенком простаивал часы в маленьком игровом салоне с компьютерами БК 00100.

У меня вопрос насчет эмуляторов. Есть ли сейчас активные проекты по разработке эмуляторов? Нет ли акивных проектов разработки эмуляторов под web assembly?
Для меня это несколько спорное утверждение. “Взрослость” — это во многом ответственность за поступки и решимость что-то сделать. Для того, чтобы любой порыв ветра не сдул нашу решимость, нужно иметь достаточно жесткий каркас внутренней правоты. Да, это некоторая закостенелость, но, с другой стороны, это же и внутренний таран.

Постигая что-то новое, все время проходишь этапы сомнения и неуверенности. Местами сложно что-то решиться сделать.

Да, можно идти циклами. Научился, стал мастером и вперед менять мир. Но не теряем ли мы при этом глубину погружения в предмет. На программистах это не так заметно, у нас есть много подпорок в виде google или stackoverflow. Но вот скрипачам или пианистам такое счастье вряд ли доступно.
Меня тут одна вещь смущает. По идее взрослый человек — это человек со своей устоявшейся картиной мира. Процесс обучения это ведь не только получение новых знаний, это еще во многом и изменение своего способа мышления.

Не получится ли так, что наш мир потихоньку становится миром вечных детей? Известная фраза: «Страшно не то, что мы теперь взрослые. Страшно, что взрослые это теперь мы!..» при этом звучит уже немного пугающе.
Спасибо за интересный рассказ. А можете чуть подробнее рассказать о стеке используемых технологий? Что вызвало наибольшие сложности в освоении? Правда ли что с возрастом мышление становится менее гибким в освоении новых вещей или это больше миф? Как это было у вас?

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Registered
Activity