[Программирование, Отладка, Julia] Debugging в Julia — два способа (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
скришнот из metal slug 3
2020 год — это определенно год странностей. Мой код тоже часто включает в себя некоторые странные ошибки. И в данном посте я хочу показать вам несколько методов отладки кода на языке julia.
Я ни с какой стороны не профессионал в этом деле, да и это справедливо для всего, о чем я пишу в блоге, так что просто имейте это в виду… Ну, на самом деле некоторые из вас платят за мою работу, так что технически я могу назвать себя профессиональным блогером, не так ли?
Во всяком случае, давайте не будем отвлекаться на эту мысль. Добро пожаловать в мой блог, если вы новичок, и добро пожаловать обратно в противном случае. Хорошо, что ваш компьютер запрашивает что-то с моего сервера.
Я предполагаю, что у вас есть некоторые базовые знания о Джулии. Следующие посты могут дать вам основы, если вы заинтересованы:
Кроме того, нужно знание базового синтаксиса.
Пример кода
Прежде чем мы начнем отладку, я хочу продемонстрировать это на некотором коде. Он достаточно короткий, чтобы показать его здесь, и содержит по крайней мере одну ошибку.
В качестве примера возьмем задачку ProjectEuler problem #21. Можете попробовать решить сами. Тут будет начало реализации возможной наивной версии.
Задача заключается в следующем: мы ищем дружественные числа меньше 10 000. Дружественное число определяется как элемент дружественной пары…
Пара двух целых чисел (a,b) дружна, если d(a) = b и d(b) = a, где d — сумма делителей, так что d(4) = 1+2 = 3.
Дана дружная пара — a = 220 и b = 284.
Мы могли бы начать с функции, которая просто берет пару и решает, является ли она дружественной.
function is_amicable(a, b)
sum_divisors(a) == b && sum_divisors(b) == a
end
Джулия всегда возвращает выходные данные последнего выполненного выражения в функции. Это означает, что ключевое слово return не обязательно.
Затем нам понадобится функция sum_divisors
function sum_divisors(a)
result = 0
for i = 1:a
if a % i == 0
result += i
end
end
return result
end
которая вызывается так
julia> is_amicable(220, 284)
false
Возможно, вы заметили ошибку, но если нет, то, вероятно, лучше не искать ее сейчас. Вместо этого следуйте по пути отладки.
Отладка с помощью Debugger.jl в REPL
Этот пост показывает вам два различных варианта отладки, и первый вариант может быть выполнен в REPL или в вашей IDE, то есть VSCode.
В этом разделе я объясню, как работать с отладчиком на REPL. (Debugger.jl)
julia> ] add Debugger
julia> using Debugger
Вы можете глянуть в пост про менеджер пакетов, если что-то не ясно.
julia> @enter is_amicable(220, 284)
In is_amicable(a, b) at REPL[7]:1
1 function is_amicable(a, b)
>2 sum_divisors(a) == b && sum_divisors(b) == a
3 end
About to run: (sum_divisors)(220)
1|debug>
Я набил @enter is_amicable(220, 284), чтобы получить этот вывод. Кстати, я только что скопировал две функции, которые я определил ранее, в REPL. С другой стороны, Вы можете создать для этого файл amicable.jl и использовать Revise и include (см. REPL and Revise.jl).
В случае файла номера строк, вероятно, более полезны.
Я вернусь через секунду...
julia> using Revise
julia> includet("amicable.jl")
julia> using Debugger
julia> @enter is_amicable(220, 284)
In is_amicable(a, b) at /home/ole/Julia/opensources/blog/2020-10-27-basics-debugging/amicable.jl:1
1 function is_amicable(a, b)
>2 sum_divisors(a) == b && sum_divisors(b) == a
3 end
About to run: (sum_divisors)(220)
1|debug>
Готово. Хорошо, теперь как уже упоминалось, в конце мы собираемся запустить sum_divisors(220).
Последняя строка 1|debug> дает нам возможность исследовать дальше, прыгая по коду, в том числе и низкоуровневому, и много чего еще всякого интересного.
Можно посмотреть полный список команд: Debugger.jl commands
Вы также можете ввести ? в режиме отладчика и нажать клавишу enter, чтобы увидеть список команд
Давайте начнем с n — шаг к следующей строке.
1|debug> n
In is_amicable(a, b) at /home/ole/Julia/opensources/blog/2020-10-27-basics-debugging/amicable.jl:1
1 function is_amicable(a, b)
>2 sum_divisors(a) == b && sum_divisors(b) == a
3 end
About to run: return false
Значит sum_divisors(220) != 284. Мы, вероятно, хотим перейти к вызову sum_divisors(220).
Мы всегда можем выпрыгнуть из сеанса отладки с помощью q, а затем начать все сначала
Начнем снова с @enter is_amicable(220, 284) и используем s для шага в функцию
1|debug> s
In sum_divisors(a) at /home/ole/Julia/opensources/blog/2020-10-27-basics-debugging/amicable.jl:5
5 function sum_divisors(a)
> 6 result = 0
7 for i = 1:a
8 if a % i == 0
9 result += i
10 end
About to run: 0
1|debug>
А дальше продолжаем использовать n, но вы, вероятно, можете себе представить, что это займет некоторое время.
Какие еще инструменты у нас есть, чтобы проверить, что происходит?
Некоторые из вас могут подумать: Хорошо, мы должны, по крайней мере, выяснить, что мы возвращаем, и мы можем просто вызвать sum_divisors(220). Это, вероятно, правильно, но не показывает возможности отладчика. Давайте представим, что мы имеем доступ только к режиму отладчика и не можем просто вызвать функцию.
В общем, этот способ узнавания нового, скрывая то, что мы уже знаем, довольно эффективен.
Я думаю, что пришло время, чтобы представить силу точек останова.
Вместо того, чтобы ползти по программе строка за строкой, часто разумно перейти к определенной точке, запустив код до тех пор, пока эта точка не будет достигнута.
Вы можете сделать это с помощью bp add, а затем указать файл, номер строки и возможное условие. Вы можете увидеть все параметры с помощью ? в режиме отладки.
В наших интересах будет поставить bp add 12. После этого мы можем использовать команду c, которая расшифровывается как continue (до точки останова).
1|debug> c
Hit breakpoint:
In sum_divisors(a) at /home/ole/Julia/opensources/blog/2020-10-27-basics-debugging/amicable.jl:5
8 if a % i == 0
9 result += i
10 end
11 end
>12 return result
13 end
About to run: return 504
Итак, теперь мы знаем, что оно возвращает 504 вместо 284. Теперь мы можем использовать `, чтобы перейти в режим Джулии. (Я знаю, что это вроде как запрещено нашими правилами, но время от времени это имеет смысл, и мы видим, что мы находимся в 1|julia>, а не в julia>, так что я думаю, что все в порядке...)
504-284 — это не самый сложный расчет, но мы можем использовать julia, чтобы сделать это за нас, не выходя полностью из режима отладки, используя:
1|debug> `
1|julia> 504-284
220
Похоже, мы нашли ошибку. Мы добавляем само число к результату, но оно на самом деле не считается за множитель.
А это значит, что мы можем сделать:
function sum_divisors(a)
result = 0
#for i = 1:a
for i = 1:a-1
if a % i == 0
result += i
end
end
return result
end
чтобы избежать эту проблему.
Да, я знаю, что мы можем избежать большего количества чисел, чтобы быть быстрее
Мы можем выйти из режима вычислений с помощью backspace, а затем q, чтобы выйти из режима отладки. Запускаем
julia> is_amicable(220, 284)
true
и видим, что мы выковыряли этот баг.
Давайте запустим его в последний раз в сеансе отладки и посмотрим на переменные. Снова перейдем к точке останова c и запустим
1|debug> w add i
1] i: 219
1|debug> w add a
1] i: 219
2] a: 220
Теперь мы видим переменные. Если мы снова нажмем c, то снова перейдем к точке разрыва (для очередного вычисления sum_divisors(284) == 220).
Мы можем снова использовать букву w, чтобы увидеть список переменных в области видимости:
1|debug> w
1] i: 283
2] a: 284
Есть еще несколько способов поиграть, например, шагнуть в код, показать низкоуровневый код и многое другое. Этого должно быть достаточно для знакомства.
В следующем разделе я хочу привести вам тот же пример с помощью редактора кода visual studio с расширением julialang.
Использование VSCode
Я думаю, что большинство разработчиков Julia используют VSCode IDE и, по крайней мере, иногда, vim, emacs или еще что-то такое неудобное… Ладно, это, наверное, просто слишком неудобно для меня
Определенно пришло время переключиться на VSCode с Atom/Juno, поскольку расширение Julia теперь разработано для VSCode вместо Atom.
Поскольку это IDE, имеет смысл иметь более визуальный отладчик, чем тот, который описан в предыдущем разделе.
Он довольно прост в навигации, и по умолчанию вы получаете больше выходных данных.
Чтобы начать сеанс отладки, вы нажимаете на кнопку с ошибкой и воспроизводите знак слева, пока у вас открыт файл julia.
Я добавил последнюю строку is_amicable(220, 284), так как VSCode просто запускает программу.
Вы можете добавить точку останова, щелкнув слева от номера каждой строки.
Я сделал снимок экрана после того, как сделал эти шаги, и последним шагом было нажатие на кнопку отладки.
Через несколько секунд сеанс отладки приостанавливается по мере достижения точки останова. С левой стороны можно увидеть локальные переменные в этой позиции. Это этап после того, как я исправил ошибку, так что вы можете видеть, что возвращается правильный результат "284". Однако вы также получаете значение для a и i.
Короче, все то же, что мы делали раньше с нашими переменными, но там нам пришлось вручную добавлять их.
Теперь мы также можем вручную добавлять выражения для наблюдения. Это можно сделать в части Watch ниже Variables, которая находится за пределами скриншота. Довольно приятно иметь возможность добавлять точки останова одним щелчком мыши, а также иметь локальные переменные, показанные слева по умолчанию.
Вы можете спросить себя: Ну, на самом деле это не два способа отладки, не так ли? Это примерно одно и то же, только с другим графическим интерфейсом.
Это правда! Вот почему я сейчас перехожу к следующему разделу поста
Infiltrator.jl для скорости
Существует одна огромная проблема с отладчиком Julia, которая решается по-разному различными пакетами. Проблема в том, что отладчик работает в интерпретируемом режиме, что делает его очень медленным. Если вы отлаживали код C++, то знаете, что отладчик там тоже работает медленнее, чем выполнение, но для Джулии это, на мой взгляд, огромная проблема.
Можно перейти в скомпилированный режим с отладчиком, но это экспериментально, и, по крайней мере, для меня он никогда не останавливался на точке останова.
Некоторые другие пакеты пытаются исправить эту проблему, делая какую-то причудливую магию, но я лично большой поклонник Infiltrator.jl. Правда, некоторое время не было никаких обновлений, и у меня есть некоторые проблемы с ним, но мне нравится сама идея.
Это также один из тех проектов с менее чем 100 звездами. Я хочу подтолкнуть его к этой вехе, так что если вам нравится то, что вы видите в этом разделе, пожалуйста, щелкните им звездочку.
Infiltrator.jl идет совершенно другим путем. Прежде всего, вам нужно немного изменить свой код. Он предоставляет макрос @infiltrate. О боже, как я люблю это название
Макрос примерно такой же, как и предыдущая точка останова. Всякий раз, когда достигается нужная строка, открывается новый вид режима REPL. Это немного усложняет переключение между режимом отладки и обычным режимом запуска, так как вам нужно добавить или удалить макросы @infiltrate, но я думаю, что это нормально.
Я снова продемонстрирую это на примере разобранном выше. Подобного рода использование было в debugging ConstraintSolver.jl.
Я скопировал код сверху и просто добавил using Infiltrator и @infiltrate.
using Infiltrator
function is_amicable(a, b)
sum_divisors(a) == b && sum_divisors(b) == a
end
function sum_divisors(a)
result = 0
for i = 1:a-1
if a % i == 0
result += i
end
end
@infiltrate
return result
end
is_amicable(220, 284)
При запуске кода с include("amicable.jl") получаем:
Hit `@infiltrate` in sum_divisors(::Int64) at amicable.jl:14:
debug>
Это означает, что мы знаем, какая точка останова была достигнута, и видим тип переменной, которую мы назвали sum_divisors. Однако в отличие от Debugger.jl мы не видим кода.
Вы можете снова увидеть раздел справки с помощью ?
debug> ?
Code entered is evaluated in the current function's module. Note that you cannot change local
variables.
The following commands are special cased:
- `@trace`: Print the current stack trace.
- `@locals`: Print local variables.
- `@stop`: Stop infiltrating at this `@infiltrate` spot.
Exit this REPL mode with `Ctrl-D`, and clear the effect of `@stop` with `Infiltrator.clear_stop()`.
Существует не так уж много команд, поэтому мы можем просто попробовать их одну за другой:
debug> @trace
[1] sum_divisors(::Int64) at amicable.jl:14
[2] is_amicable(::Int64, ::Int64) at amicable.jl:4
[3] top-level scope at amicable.jl:18
[4] include(::String) at client.jl:457
Таким образом, мы пришли из is_amicable и можем видеть типы, а также имя файла и номер строки, что полезно при использовании multiple dispatch.
debug> @locals
- result::Int64 = 284
- a::Int64 = 220
мы можем видеть локальные переменные, которые похожи на те, которые мы видели в представлении переменных VSCode.
Кроме того, мы можем просто вычислять выражения прям в этом режиме. Для Infiltrator.jl нет необходимости использовать `, чтобы переключиться на вычисления.
debug> a == 220
true
Вы можете использовать @stop, чтобы больше не останавливаться на этой вехе, и Infiltrator.clear_stop(), чтобы очистить эти остановки.
Давайте не будем использовать @stop сейчас, а вместо этого перейдем к следующей точке @infiltrate с помощью CTRL-D:
Hit `@infiltrate` in sum_divisors(::Int64) at amicable.jl:14:
debug>
таким образом, мы находимся в той же точке останова, но со вторым вызовом. К сожалению, невозможно использовать клавишу со стрелкой вверх, чтобы перейти через историю команд, которые мы использовали, так что нам нужно снова ввести @locals, если мы хотим их увидеть.
Я открыл такую тему и попытался разрешить ее сам, но мне это не удалось. Было бы здорово, если бы это когда-нибудь было реализовано, потому что я думаю, что было бы очень полезно отлаживать быстрее таким образом.
Давайте рассмотрим сравнение двух различных способов в следующем разделе.
Выводы
Мы посмотрели на Debugger. jl, который дает вам всю информацию, которая может понадобиться в вашем REPL.
Поэтому он не зависит от редактора.
Следующий инструмент, который я упомянул, был дебагер в VSCode который является в основном просто графическим интерфейсом для Debugger.jl. Вероятно, его удобнее использовать людям, которые любят работать с IDE. Хотя в Debugger.jl могут быть некоторые опции, которые недоступны в графическом интерфейсе, как это часто бывает.
Оба этих инструмента дают то преимущество, что вы можете шаг за шагом переходить через свой код и исследовать все, что захотите. Вы можете взглянуть на низкоуровневый код (по крайней мере, в Debugger.jl). Это, вероятно, то, что каждый ожидает сделать с отладчиком. Проблема просто в том, что он слишком медленный во многих случаях использования, например, когда вы хотите отладить свой собственный пакет с 1000 строками кода.
В таком случае Infiltrator.jl — это путь, по крайней мере для меня, и пока скомпилированный режим Debugger.jl работает недостаточно хорошо. У него есть и другие недостатки, так как не бывает чтоб все и сразу, но я думаю, что он часто превосходит использование println, поскольку можно распечатать все, что в данный момент интересует в данной точке останова, и увидеть все локальные переменные за один раз.
Спасибо за то, что дочитали и особая благодарность моим 10 покровителям!
Я буду держать вас в курсе Twitter OpenSourcES.
===========
Источник:
habr.com
===========
===========
Автор оригинала: Ole Kröger
===========Похожие новости:
- [Программирование, C++, Компиляторы, IT-стандарты] С++23: международный стандарт на удалёнке
- [Программирование, C++, C] Финальный релиз этого года — CLion 2020.3! С новыми функциями в отладчике, проверками MISRA и улучшениями для Qt
- [Программирование, Go] Методы организации DI и жизненного цикла приложения в GO
- [Программирование, Обработка изображений, Машинное обучение, Искусственный интеллект] Scaled YOLO v4 самая лучшая нейронная сеть для обнаружения объектов на датасете MS COCO
- [JavaScript, Программирование, Node.JS] Декораторы в JavaScript с нуля (перевод)
- [JavaScript, Программирование, ReactJS] Начинающим React-разработчикам: приложение со списком дел (покупок) (перевод)
- [Программирование] kotlinx.coroutines 1.4.0: представляем StateFlow и SharedFlow (перевод)
- [Программирование, Разработка под Android] Подменяем Runtime permissions в Android
- [Программирование, Go, Микросервисы] Создаем высокопроизводительные микросервисы с помощью gRPC, Ballerina и Go (перевод)
- [Open source, Программирование, C++] Не хочется ждать в очереди? Напишем свой диспетчер для SObjectizer с приоритетной доставкой
Теги для поиска: #_programmirovanie (Программирование), #_otladka (Отладка), #_julia, #_julia_language, #_otladka (отладка), #_interpretator (интерпретатор), #_zhuki (жуки), #_pauki (пауки), #_programmirovanie (
Программирование
), #_otladka (
Отладка
), #_julia
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:04
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
скришнот из metal slug 3 2020 год — это определенно год странностей. Мой код тоже часто включает в себя некоторые странные ошибки. И в данном посте я хочу показать вам несколько методов отладки кода на языке julia. Я ни с какой стороны не профессионал в этом деле, да и это справедливо для всего, о чем я пишу в блоге, так что просто имейте это в виду… Ну, на самом деле некоторые из вас платят за мою работу, так что технически я могу назвать себя профессиональным блогером, не так ли? Во всяком случае, давайте не будем отвлекаться на эту мысль. Добро пожаловать в мой блог, если вы новичок, и добро пожаловать обратно в противном случае. Хорошо, что ваш компьютер запрашивает что-то с моего сервера. Я предполагаю, что у вас есть некоторые базовые знания о Джулии. Следующие посты могут дать вам основы, если вы заинтересованы: Кроме того, нужно знание базового синтаксиса. Пример кода Прежде чем мы начнем отладку, я хочу продемонстрировать это на некотором коде. Он достаточно короткий, чтобы показать его здесь, и содержит по крайней мере одну ошибку. В качестве примера возьмем задачку ProjectEuler problem #21. Можете попробовать решить сами. Тут будет начало реализации возможной наивной версии. Задача заключается в следующем: мы ищем дружественные числа меньше 10 000. Дружественное число определяется как элемент дружественной пары… Пара двух целых чисел (a,b) дружна, если d(a) = b и d(b) = a, где d — сумма делителей, так что d(4) = 1+2 = 3. Дана дружная пара — a = 220 и b = 284. Мы могли бы начать с функции, которая просто берет пару и решает, является ли она дружественной. function is_amicable(a, b)
sum_divisors(a) == b && sum_divisors(b) == a end Джулия всегда возвращает выходные данные последнего выполненного выражения в функции. Это означает, что ключевое слово return не обязательно.
function sum_divisors(a)
result = 0 for i = 1:a if a % i == 0 result += i end end return result end которая вызывается так julia> is_amicable(220, 284)
false Возможно, вы заметили ошибку, но если нет, то, вероятно, лучше не искать ее сейчас. Вместо этого следуйте по пути отладки. Отладка с помощью Debugger.jl в REPL Этот пост показывает вам два различных варианта отладки, и первый вариант может быть выполнен в REPL или в вашей IDE, то есть VSCode. В этом разделе я объясню, как работать с отладчиком на REPL. (Debugger.jl) julia> ] add Debugger
julia> using Debugger Вы можете глянуть в пост про менеджер пакетов, если что-то не ясно. julia> @enter is_amicable(220, 284)
In is_amicable(a, b) at REPL[7]:1 1 function is_amicable(a, b) >2 sum_divisors(a) == b && sum_divisors(b) == a 3 end About to run: (sum_divisors)(220) 1|debug> Я набил @enter is_amicable(220, 284), чтобы получить этот вывод. Кстати, я только что скопировал две функции, которые я определил ранее, в REPL. С другой стороны, Вы можете создать для этого файл amicable.jl и использовать Revise и include (см. REPL and Revise.jl). В случае файла номера строк, вероятно, более полезны. Я вернусь через секунду... julia> using Revise
julia> includet("amicable.jl") julia> using Debugger julia> @enter is_amicable(220, 284) In is_amicable(a, b) at /home/ole/Julia/opensources/blog/2020-10-27-basics-debugging/amicable.jl:1 1 function is_amicable(a, b) >2 sum_divisors(a) == b && sum_divisors(b) == a 3 end About to run: (sum_divisors)(220) 1|debug> Готово. Хорошо, теперь как уже упоминалось, в конце мы собираемся запустить sum_divisors(220). Последняя строка 1|debug> дает нам возможность исследовать дальше, прыгая по коду, в том числе и низкоуровневому, и много чего еще всякого интересного. Можно посмотреть полный список команд: Debugger.jl commands Вы также можете ввести ? в режиме отладчика и нажать клавишу enter, чтобы увидеть список команд
1|debug> n
In is_amicable(a, b) at /home/ole/Julia/opensources/blog/2020-10-27-basics-debugging/amicable.jl:1 1 function is_amicable(a, b) >2 sum_divisors(a) == b && sum_divisors(b) == a 3 end About to run: return false Значит sum_divisors(220) != 284. Мы, вероятно, хотим перейти к вызову sum_divisors(220). Мы всегда можем выпрыгнуть из сеанса отладки с помощью q, а затем начать все сначала Начнем снова с @enter is_amicable(220, 284) и используем s для шага в функцию 1|debug> s
In sum_divisors(a) at /home/ole/Julia/opensources/blog/2020-10-27-basics-debugging/amicable.jl:5 5 function sum_divisors(a) > 6 result = 0 7 for i = 1:a 8 if a % i == 0 9 result += i 10 end About to run: 0 1|debug> А дальше продолжаем использовать n, но вы, вероятно, можете себе представить, что это займет некоторое время. Какие еще инструменты у нас есть, чтобы проверить, что происходит? Некоторые из вас могут подумать: Хорошо, мы должны, по крайней мере, выяснить, что мы возвращаем, и мы можем просто вызвать sum_divisors(220). Это, вероятно, правильно, но не показывает возможности отладчика. Давайте представим, что мы имеем доступ только к режиму отладчика и не можем просто вызвать функцию. В общем, этот способ узнавания нового, скрывая то, что мы уже знаем, довольно эффективен. Я думаю, что пришло время, чтобы представить силу точек останова. Вместо того, чтобы ползти по программе строка за строкой, часто разумно перейти к определенной точке, запустив код до тех пор, пока эта точка не будет достигнута. Вы можете сделать это с помощью bp add, а затем указать файл, номер строки и возможное условие. Вы можете увидеть все параметры с помощью ? в режиме отладки. В наших интересах будет поставить bp add 12. После этого мы можем использовать команду c, которая расшифровывается как continue (до точки останова). 1|debug> c
Hit breakpoint: In sum_divisors(a) at /home/ole/Julia/opensources/blog/2020-10-27-basics-debugging/amicable.jl:5 8 if a % i == 0 9 result += i 10 end 11 end >12 return result 13 end About to run: return 504 Итак, теперь мы знаем, что оно возвращает 504 вместо 284. Теперь мы можем использовать `, чтобы перейти в режим Джулии. (Я знаю, что это вроде как запрещено нашими правилами, но время от времени это имеет смысл, и мы видим, что мы находимся в 1|julia>, а не в julia>, так что я думаю, что все в порядке...) 504-284 — это не самый сложный расчет, но мы можем использовать julia, чтобы сделать это за нас, не выходя полностью из режима отладки, используя: 1|debug> `
1|julia> 504-284 220 Похоже, мы нашли ошибку. Мы добавляем само число к результату, но оно на самом деле не считается за множитель. А это значит, что мы можем сделать: function sum_divisors(a)
result = 0 #for i = 1:a for i = 1:a-1 if a % i == 0 result += i end end return result end чтобы избежать эту проблему. Да, я знаю, что мы можем избежать большего количества чисел, чтобы быть быстрее
julia> is_amicable(220, 284)
true и видим, что мы выковыряли этот баг. Давайте запустим его в последний раз в сеансе отладки и посмотрим на переменные. Снова перейдем к точке останова c и запустим 1|debug> w add i
1] i: 219 1|debug> w add a 1] i: 219 2] a: 220 Теперь мы видим переменные. Если мы снова нажмем c, то снова перейдем к точке разрыва (для очередного вычисления sum_divisors(284) == 220). Мы можем снова использовать букву w, чтобы увидеть список переменных в области видимости: 1|debug> w
1] i: 283 2] a: 284 Есть еще несколько способов поиграть, например, шагнуть в код, показать низкоуровневый код и многое другое. Этого должно быть достаточно для знакомства. В следующем разделе я хочу привести вам тот же пример с помощью редактора кода visual studio с расширением julialang. Использование VSCode Я думаю, что большинство разработчиков Julia используют VSCode IDE и, по крайней мере, иногда, vim, emacs или еще что-то такое неудобное… Ладно, это, наверное, просто слишком неудобно для меня Определенно пришло время переключиться на VSCode с Atom/Juno, поскольку расширение Julia теперь разработано для VSCode вместо Atom. Поскольку это IDE, имеет смысл иметь более визуальный отладчик, чем тот, который описан в предыдущем разделе. Он довольно прост в навигации, и по умолчанию вы получаете больше выходных данных. Чтобы начать сеанс отладки, вы нажимаете на кнопку с ошибкой и воспроизводите знак слева, пока у вас открыт файл julia. Я добавил последнюю строку is_amicable(220, 284), так как VSCode просто запускает программу. Вы можете добавить точку останова, щелкнув слева от номера каждой строки. Я сделал снимок экрана после того, как сделал эти шаги, и последним шагом было нажатие на кнопку отладки. Через несколько секунд сеанс отладки приостанавливается по мере достижения точки останова. С левой стороны можно увидеть локальные переменные в этой позиции. Это этап после того, как я исправил ошибку, так что вы можете видеть, что возвращается правильный результат "284". Однако вы также получаете значение для a и i. Короче, все то же, что мы делали раньше с нашими переменными, но там нам пришлось вручную добавлять их. Теперь мы также можем вручную добавлять выражения для наблюдения. Это можно сделать в части Watch ниже Variables, которая находится за пределами скриншота. Довольно приятно иметь возможность добавлять точки останова одним щелчком мыши, а также иметь локальные переменные, показанные слева по умолчанию. Вы можете спросить себя: Ну, на самом деле это не два способа отладки, не так ли? Это примерно одно и то же, только с другим графическим интерфейсом. Это правда! Вот почему я сейчас перехожу к следующему разделу поста Infiltrator.jl для скорости Существует одна огромная проблема с отладчиком Julia, которая решается по-разному различными пакетами. Проблема в том, что отладчик работает в интерпретируемом режиме, что делает его очень медленным. Если вы отлаживали код C++, то знаете, что отладчик там тоже работает медленнее, чем выполнение, но для Джулии это, на мой взгляд, огромная проблема. Можно перейти в скомпилированный режим с отладчиком, но это экспериментально, и, по крайней мере, для меня он никогда не останавливался на точке останова. Некоторые другие пакеты пытаются исправить эту проблему, делая какую-то причудливую магию, но я лично большой поклонник Infiltrator.jl. Правда, некоторое время не было никаких обновлений, и у меня есть некоторые проблемы с ним, но мне нравится сама идея. Это также один из тех проектов с менее чем 100 звездами. Я хочу подтолкнуть его к этой вехе, так что если вам нравится то, что вы видите в этом разделе, пожалуйста, щелкните им звездочку. Infiltrator.jl идет совершенно другим путем. Прежде всего, вам нужно немного изменить свой код. Он предоставляет макрос @infiltrate. О боже, как я люблю это название Макрос примерно такой же, как и предыдущая точка останова. Всякий раз, когда достигается нужная строка, открывается новый вид режима REPL. Это немного усложняет переключение между режимом отладки и обычным режимом запуска, так как вам нужно добавить или удалить макросы @infiltrate, но я думаю, что это нормально. Я снова продемонстрирую это на примере разобранном выше. Подобного рода использование было в debugging ConstraintSolver.jl. Я скопировал код сверху и просто добавил using Infiltrator и @infiltrate. using Infiltrator
function is_amicable(a, b) sum_divisors(a) == b && sum_divisors(b) == a end function sum_divisors(a) result = 0 for i = 1:a-1 if a % i == 0 result += i end end @infiltrate return result end is_amicable(220, 284) При запуске кода с include("amicable.jl") получаем: Hit `@infiltrate` in sum_divisors(::Int64) at amicable.jl:14:
debug> Это означает, что мы знаем, какая точка останова была достигнута, и видим тип переменной, которую мы назвали sum_divisors. Однако в отличие от Debugger.jl мы не видим кода. Вы можете снова увидеть раздел справки с помощью ? debug> ?
Code entered is evaluated in the current function's module. Note that you cannot change local variables. The following commands are special cased: - `@trace`: Print the current stack trace. - `@locals`: Print local variables. - `@stop`: Stop infiltrating at this `@infiltrate` spot. Exit this REPL mode with `Ctrl-D`, and clear the effect of `@stop` with `Infiltrator.clear_stop()`. Существует не так уж много команд, поэтому мы можем просто попробовать их одну за другой: debug> @trace
[1] sum_divisors(::Int64) at amicable.jl:14 [2] is_amicable(::Int64, ::Int64) at amicable.jl:4 [3] top-level scope at amicable.jl:18 [4] include(::String) at client.jl:457 Таким образом, мы пришли из is_amicable и можем видеть типы, а также имя файла и номер строки, что полезно при использовании multiple dispatch. debug> @locals
- result::Int64 = 284 - a::Int64 = 220 мы можем видеть локальные переменные, которые похожи на те, которые мы видели в представлении переменных VSCode. Кроме того, мы можем просто вычислять выражения прям в этом режиме. Для Infiltrator.jl нет необходимости использовать `, чтобы переключиться на вычисления. debug> a == 220
true Вы можете использовать @stop, чтобы больше не останавливаться на этой вехе, и Infiltrator.clear_stop(), чтобы очистить эти остановки. Давайте не будем использовать @stop сейчас, а вместо этого перейдем к следующей точке @infiltrate с помощью CTRL-D: Hit `@infiltrate` in sum_divisors(::Int64) at amicable.jl:14:
debug> таким образом, мы находимся в той же точке останова, но со вторым вызовом. К сожалению, невозможно использовать клавишу со стрелкой вверх, чтобы перейти через историю команд, которые мы использовали, так что нам нужно снова ввести @locals, если мы хотим их увидеть. Я открыл такую тему и попытался разрешить ее сам, но мне это не удалось. Было бы здорово, если бы это когда-нибудь было реализовано, потому что я думаю, что было бы очень полезно отлаживать быстрее таким образом. Давайте рассмотрим сравнение двух различных способов в следующем разделе. Выводы Мы посмотрели на Debugger. jl, который дает вам всю информацию, которая может понадобиться в вашем REPL. Поэтому он не зависит от редактора. Следующий инструмент, который я упомянул, был дебагер в VSCode который является в основном просто графическим интерфейсом для Debugger.jl. Вероятно, его удобнее использовать людям, которые любят работать с IDE. Хотя в Debugger.jl могут быть некоторые опции, которые недоступны в графическом интерфейсе, как это часто бывает. Оба этих инструмента дают то преимущество, что вы можете шаг за шагом переходить через свой код и исследовать все, что захотите. Вы можете взглянуть на низкоуровневый код (по крайней мере, в Debugger.jl). Это, вероятно, то, что каждый ожидает сделать с отладчиком. Проблема просто в том, что он слишком медленный во многих случаях использования, например, когда вы хотите отладить свой собственный пакет с 1000 строками кода. В таком случае Infiltrator.jl — это путь, по крайней мере для меня, и пока скомпилированный режим Debugger.jl работает недостаточно хорошо. У него есть и другие недостатки, так как не бывает чтоб все и сразу, но я думаю, что он часто превосходит использование println, поскольку можно распечатать все, что в данный момент интересует в данной точке останова, и увидеть все локальные переменные за один раз. Спасибо за то, что дочитали и особая благодарность моим 10 покровителям! Я буду держать вас в курсе Twitter OpenSourcES. =========== Источник: habr.com =========== =========== Автор оригинала: Ole Kröger ===========Похожие новости:
Программирование ), #_otladka ( Отладка ), #_julia |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:04
Часовой пояс: UTC + 5