Опубликован релиз языка программирования Julia 1.12, сочетающего такие качества как высокая производительность, поддержка динамической типизации и встроенные средства для параллельного программирования. Синтаксис Julia близок к MATLAB с заимствованием некоторых элементов из Ruby и Lisp. Метод манипуляции строками напоминает Perl. Код проекта распространяется под лицензией MIT.
Ключевые особенности языка:
- Высокая производительность: одной из ключевых целей проекта является достижение производительности близкой к программам на языке Си. Компилятор Julia основан на наработках проекта LLVM и генерирует эффективный нативный машинный код для многих целевых платформ;
- Поддержка различных парадигм программирования, включая элементы объектно-ориентированного и функционального программирования. Стандартная библиотека предоставляет в том числе функции для асинхронного ввода/вывода, управления процессами, ведения логов, профилирования и управления пакетами;
- Динамическая типизация: язык не требует явного определения типов для переменных по аналогии со скриптовыми языками программирования. Поддерживается интерактивный режим работы;
- Опциональная возможность явного указания типов;
- Синтаксис, превосходно подходящий для численных вычислений, научных расчётов, систем машинного обучения и визуализации данных. Поддержка многих числовых типов данных и средств для распараллеливания вычислений.
- Возможность прямого вызова функций из библиотек на языке Си без дополнительных прослоек.
Основные изменения в Julia 1.12:
- Новые возможности языка
- Экспериментальный параметр "--trim", позволяющий создавать более компактные бинарные файлы за счёт удаления кода, который не достижим из указанных точек входа. Точки входа можно помечать с помощью "Base.Experimental.entrypoint". С этой опцией может работать не весь код.
- Переопределение констант теперь чётко определено и следует семантике "world age". Допустимы дополнительные переопределения (например, типов).
- В функцию "names" добавлен новый параметр "usings::Bool", заставляющий функцию вернуть все имена, видимые через "using".
- Семейство макросов "@atomic" теперь поддерживает синтаксис присваивания ссылок, например: "@atomic :monotonic v[3] += 4", который атомарно изменяет "v[3]" с семантикой монотонного упорядочения. Поддерживаемый синтаксис включает:
- атомарное чтение ("x = @atomic v[3]"),
- атомарное присваивание ("@atomic v[3] = 4"),
- атомарное изменение ("@atomic v[3] += 2"),
- атомарное однократное присваивание ("@atomiconce v[3] = 2"),
- атомарный обмен ("x = @atomicswap v[3] = 2"),
- атомарную замену ("x = @atomicreplace v[3] 2=>5").
- Новый параметр "--task-metrics=yes", включающий сбор информации о времени выполнения каждой задачи, который можно включать/выключать и во время работы через "Base.Experimental.task_metrics(::Bool)". Доступные метрики:
- фактическое время выполнения задачи, включая компиляцию и сбор мусора ("Base.Experimental.task_running_time_ns"),
- время от момента, когда задача начала выполняться до завершения("Base.Experimental.task_wall_time_ns").
- Поддержка Unicode 16.
- "Threads.@spawn" теперь принимает аргумент ":samepool" для указания того же пула потоков, что и вызывающий код. "Threads.@spawn :samepool foo()" — сокращение для "Threads.@spawn Threads.threadpool() foo()".
- Макрос "@ccall" теперь может принимать аргумент "gc_safe". Если он равен true, то во время вызова "ccall" рантайм может осуществлять сборку мусора параллельно.
- Изменения языка
- При замене метода эквивалентным по сигнатуре, существующий метод не удаляется. Вместо этого новый метод становится приоритетным. Если новый метод будет удалён, старый метод снова начнёт работать. Это полезно, например, в фреймворках тестирования с подменой (SparseArrays, Pluto, Mocking и др.), так как не нужно явно восстанавливать старый метод. В настоящее время для этой ситуации требуется повторная компиляция, но возможно в будущем удастся переиспользовать старые результаты.
- Развертывание макросов больше не будет сразу рекурсивно входить в выражения "Expr(:toplevel)" из макросов. Вместо этого развёртывание ":toplevel" будет отложено до времени выполнения. Это позволяет более поздним выражениям в том же ":toplevel" использовать макросы, определённые ранее.
- Тривиальные бесконечные циклы (такие как "while true; end") больше не считаются неопределённым поведением. Бесконечные циклы, в которых что-то происходит (например, с побочными эффектами или sleep), никогда не были и не являются неопределённым поведением.
- Одновременная пометка идентификатора как "public" и "export" теперь является ошибкой.
- Ошибки во время выполнения "getfield" теперь порождают новый тип исключений "FieldError" вместо общего "ErrorException".
- Макросы в позиции объявления функций теперь не требуют круглых скобок. Например, допустимо "function @main(args) ... end", тогда как ранее требовалось "function (@main)(args) ... end".
- Вызов "using" по имени пакета внутри самого пакета (особенно актуально для вложенных модулей) теперь явно использует этот пакет без просмотра Manifest и окружения, так же, как "..Name". Это лучше соответствует ожидаемому поведению.
- Улучшения компилятора/рантайма
- Сгенерированный LLVM промежуточный код (IR) теперь использует типы указателей вместо передачи указателей в форме целых чисел. Это касается "llvmcall": встроенный LLVM IR следует обновить, заменив "i32"/"i64" на "i8*" или "ptr" и убрав ненужные конверсии "ptrtoint"/"inttoptr". Для совместимости IR с целочисленными указателями всё ещё поддерживается, но выдаёт предупреждение.
- Изменения параметров командной строки
- Флаг "-m/--module" можно передать для запуска функции "main" внутри пакета с набором аргументов. Эта функция должна быть объявлена через "@main", указывая, что это точка входа.
- Включение/отключение цветового вывода в Julia теперь можно контролировать с помощью переменных окружения "NO_COLOR" и "FORCE_COLOR". Эти переменные также учитываются системой сборки Julia.
- "--project=@temp" запускает Julia с временным окружением.
- Новый параметр "--trace-compile-timing" выводит время компиляции каждого метода, который выводится "--trace-compile", в миллисекундах.
- "--trace-compile" теперь выводит перекомпилированные методы жёлтым цветом или добавляет комментарий, если цвет недоступен.
- Новый параметр "--trace-dispatch" выводит методы, которые динамически распределяются.
- Изменения многопоточности
- Julia теперь по умолчанию использует 1 «интерактивный» поток, в дополнение к 1 основному «рабочему» потоку, т.е. "-t1,1". Это означает, что основная задача и REPL (в интерактивном режиме), которые оба работают в потоке 1, теперь выполняются в интерактивном пуле. Цикл ввода-вывода libuv тоже работает в потоке 1, что обеспечивает эффективное использование рабочего пула, используемого "Threads.@spawn". Запрос ровно 1 потока ("-t1"/"JULIA_NUM_THREADS=1") или 0 интерактивных потоков отключает интерактивный поток: "-t1,0", "JULIA_NUM_THREADS=1,0" или "-tauto,0". Запрос более 1 потока включает интерактивный поток; например, "-t2" эквивалентно "-t2,1". Напоминаем: буферы не следует привязывать к "threadid()".
- Определены новые типы для шаблона кода, который должен выполняться один раз на процесс — тип "OncePerProcess{T}" позволяет определить функцию, которая выполнится ровно один раз, когда её впервые вызовут, а затем будет всегда возвращать одно и то же значение типа "T" при последующих вызовах. Также существуют типы "OncePerThread{T}" и "OncePerTask{T}" для аналогичного использования с потоками или задачами.
- Изменения системы сборки
- Добавлены новые файлы Makefile для сборки Julia и LLVM с использованием BOLT (Binary Optimization and Layout Tool). См.
"contrib/bolt" и "contrib/pgo-lto-bolt".
- Новые библиотечные функции
- "logrange(start, stop; length)" создаёт диапазон с постоянным коэффициентом (ratio), а не постоянным шагом.
- Новая функция "isfull(c::Channel)" проверяет, будет ли блокироваться "put!(c, some_value)".
- "waitany(tasks; throw=false)" и "waitall(tasks; failfast=false, throw=false)" ждёт завершения нескольких задач одновременно.
- "uuid7()" создаёт UUID версии 7, соответствующий RFC 9562.
- "insertdims(array; dims)" вставляет одноэлементные размерности в массив — операция, обратная "dropdims".
- Новый тип "Fix" обобщает "Fix1/Fix2" для фиксации одного аргумента.
- "Sys.detectwsl()" проверяет, выполняется ли Julia внутри WSL в runtime.
- Новые возможности библиотек
- "escape_string" принимает дополнительные параметры "ascii=true" (для экранирования всех не-ASCII символов) и "fullhex=true" (для использования полного 4/8-значного hex-формата в u/U-экранировке, например для совместимости с C).
- "tempname" теперь может принимать строку суффикса, чтобы имя файла включало этот суффикс и он учитывался при уникальности.
- Объекты "RegexMatch" теперь можно использовать для создания "NamedTuple" и "Dict".
- "Lockable" теперь экспортируется.
- "Base.require_one_based_indexing" и "Base.has_offset_axes" теперь публичные.
- Добавлены новые функции "ltruncate", "rtruncate" и "ctruncate" для усечения строк до ширины текста, учитывая ширину символов.
- Функция "isless" (а значит, и "cmp", сортировка и т.д.) теперь поддерживается для нулемерных "AbstractArray".
- "invoke" теперь позволяет передавать "Method" вместо сигнатуры типа.
- "invoke" теперь принимает "CodeInstance" вместо типа, что может ускорить некоторые рабочие процессы плагинов компилятора.
- "Timer(f, ...)" теперь наследует "липкость" (stickiness) родительской задачи при создании задач таймера, что можно переопределить новым аргументом "spawn". Это решает проблему, когда липкие порождённые задачи ("@async") делали родителя липким.
- "Timer" теперь имеет читаемые свойства "timeout" и "interval", а также более описательный метод "show".
- "sort" теперь поддерживает кортежи "NTuple".
- "map!(f, A)" теперь сохраняет результаты в "A", как "map!(f, A, A)" или "A .= f.(A)".
- "setprecision" с аргументом-функцией (обычно через блок "do") теперь потокобезопасен. Другие формы следует избегать, и типы должны перейти к реализации, использующей "ScopedValue".
- Изменения стандартной библиотеки
- "gcdx(0, 0)" теперь возвращает "(0, 0, 0)" вместо "(0, 1, 0)".
- "fd" возвращает "RawFD" вместо "Int".
- Пакет JuliaSyntaxHighlighting
- Новый стандартный пакет для применения подсветки синтаксиса к коду Julia, использующий "JuliaSyntax" и "StyledStrings" для реализации функции "highlight", которая создаёт "AnnotatedString" с применённой подсветкой.
- Пакет LinearAlgebra.
- "rank" теперь может принимать матрицу "QRPivoted" для оценки ранга через QR-факторизацию.
- Добавлен ключевой параметр "alg" для "eigen", "eigen!", "eigvals" и "eigvals!" для типов самосопряжённых матриц (типовое объединение "RealHermSymComplexHerm"), позволяющий переключаться между различными алгоритмами извлечения собственных значений.
- Добавлена общая версия неблокированного разложения Холецкого с выборкой поворотов (вызывается через "cholesky[!](A, RowMaximum())").
- Количество потоков BLAS по умолчанию теперь учитывает привязку процессов (process affinity), а не просто количество логических потоков системы.
- Добавлена функция "zeroslike", которая возвращает нулевые элементы для матриц с ленточным хранением. Пользовательские типы массивов могут специализировать эту функцию для правильного результата.
- Перемножение матриц "A * B" теперь вызывает "matprod_dest(A, B, T::Type)" для генерации приемника. Эта функция теперь публичная.
- Функция "haszero(T::Type)" используется для проверки, имеет ли тип "T" уникальный нулевой элемент, определённый как "zero(T)". Теперь она публичная.
- Добавлена функция "diagview", возвращающая представление (view) на конкретную диагональ матрицы "AbstractMatrix".
- Пакет Profile
- "Profile.take_heap_snapshot" теперь принимает новый параметр "redact_data::Bool", по умолчанию "true". Если разрешено, то содержимое объектов Julia (например, строк) не включается в снимок памяти.
- "Profile.print()" теперь окрашивает модули Base/Core/Package так же, как это делается в трассировках стека, а также пути (даже обрезанные) теперь кликабельны в терминалах, которые поддерживают ссылки URI и позволяют открыть указанный файл и строку в редакторе, заданном "JULIA_EDITOR".
- REPL
- Используя новую возможность "usings=true" в функции "names()", автодополнение в REPL может дополнять имена, видимые через "using".
- Автодополнение REPL теперь может завершать строки вида "[import|using] Mod: xxx|", например, завершать "using Base.Experimental: @op" до "using Base.Experimental: @opaque".
- REPL теперь выдаёт предупреждение, если имя обращается через модуль, который его не определяет (и не имеет подмодуля, который его определяет), и имя не является публичным в этом модуле. Например, "map" определён в Base, и выполнение "LinearAlgebra.map" в REPL теперь выдаст предупреждение при первом таком обращении.
- При выводе результата ввода в REPL вывод теперь обрезается до 20 KiB. Это не влияет на ручные вызовы "show", "print" и т.д.
- Автодополнение по символу "\" теперь выводит соответствующий символ или эмоджи рядом с каждым соответствующим кодовым словом.
- Пакет Test
- Если набор тестов "DefaultTestSet" завершается с ошибкой, на экран выводится генератор случайных чисел (RNG) этого набора, чтобы помочь воспроизвести стохастическую ошибку, зависящую только от состояния RNG. Также можно задать RNG для набора тестов, передав параметр "rng" в макрос "@testset":
julia
using Test, Random
@testset rng=Xoshiro(0x2e026445595ed28e, 0x07bb81ac4c54926d, 0x83d7d70843e8bad6, 0xdbef927d150af80b, 0xdbf91ddf2534f850) begin
@test rand() == 0.559472630416976
end
- Пакет InteractiveUtils
- Новые макросы "@trace_compile" и "@trace_dispatch" для выполнения выражений с параметрами "--trace-compile=stderr --trace-compile-timing" и "--trace-dispatch=stderr" соответственно.
- Внешние зависимости
- База данных terminal info ("terminfo") теперь входит в поставку Julia по умолчанию, что улучшает работу REPL, когда "terminfo" недоступен в системе. Julia можно собрать без встраивания базы, используя параметр Makefile "WITH_TERMINFO=0".
- Улучшения инструментов
- Доступен профилировщик "wall-time" для пользователей, которым нужен профилировщик с выборкой, захватывающий задачи независимо от их состояния (запланированы/выполняются). Такой профилировщик позволяет профилировать задачи с интенсивным вводом-выводом и помогает обнаружить области сильной конкуренции в системе.
|