When Trouble Strikes

2024-06-09 09:38
文章标签 trouble strikes

本文主要是介绍When Trouble Strikes,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

悲观地讲,就算使用 Ruby 编写程序也不能避免出现许多问题。即使对谈论起这个问题感到很抱歉。

但不需要担心!Ruby 拥有一些可以帮助我们调试的特性。稍后我们会看到这些特性,并且我们也会展示你使用 Ruby 时通常会遇到的问题,以及如何解决这些问题。

Ruby 调试器

Ruby 本身带有调试器,并且可以在基础系统上很方便地构建。你可以通过 -r debug 调用解释器将调试器运转,也可以添加其他 Ruby 参数以及脚本名称。

ruby -r debug [options] [programfile] [arguments]

Ruby 调试器支持一般情况下你期望调试器拥有的功能,包括设置断点,步入和下一步以及展示栈结构和变量。

它也可以列举指定对象或类定义的实例方法列表,还允许你列举和控制 Ruby 中的线程。131 页的表格 12.1 列举了在调试器中可用的命令。

如果你的 Ruby 也支持 readline,你可以将光标移回历史命令的前方,然后用编辑行的方式修改之前输入的命令。

下面通过一些简单的场景让你看看 Ruby 调试器是什么样的。

% ruby -rdebug t.rbDebug.rb
Emacs support available.
t.rb:1:def fact(n)
(rdb:1) list 1-9[1, 10] in t.rb
=> 1  def fact(n)2    if n <= 03      14    else5      n * fact(n-1)6    end7  end89  p fact(5)
(rdb:1) b 2Set breakpoint 1 at t.rb:2
(rdb:1) cbreakpoint 1, fact at t.rb:2
t.rb:2:  if n <= 0
(rdb:1) disp n1: n = 5
(rdb:1) del 1(rdb:1) watch n==1Set watchpoint 2
(rdb:1) cwatchpoint 2, fact at t.rb:fact
t.rb:1:def fact(n)
1: n = 1
(rdb:1) where--> #1  t.rb:1:in `fact'#2  t.rb:5:in `fact'#3  t.rb:5:in `fact'#4  t.rb:5:in `fact'#5  t.rb:5:in `fact'#6  t.rb:9
(rdb:1) del 2(rdb:1) c120

交互式 Ruby

如果你希望能运用 Ruby,那它拥有被称作交互式 Ruby 的能力—— 也就是 irb。irb 本质上就是 Ruby 的 shell,它与操作系统的 shell 非常相似(都是通过任务控制完成)。并且它提供了一个你可以在真实环境中使用 Ruby 操作的环境。你可以通过命令提示符运行它。

irb [irb-options] [ruby_script] [options]

irb 会显示你完成的每个表达式的值。有如下例子:

% irb
irb(main):001:0> a = 1 +irb(main):002:0* 2 * 3 /irb(main):003:0* 4 % 52
irb(main):004:0> 2+24
irb(main):005:0> def testirb(main):006:1> puts "Hello, world!"irb(main):007:1> endnil
irb(main):008:0> testHello, world!
nil
irb(main):009:0> 

irb 也允许你创建子会话,每个子会话也有自己的上下文。例如,你可以用与原始会话一致的上下文创建子会话,或者通过特定类或实例的上下文完成对子会话的创建。普通的会话在 126 页图 12.1 中展示,而且也显示了如何创建子会话和对它们进行切换。

对于所有关于 irb 支持的命令的描述可以查看 517 页开始的内容。

和调试器一样,如果你的 Ruby 版本是构建于 GNU Readline 支持之上,你便可以使用箭头键或者 vi 风格绑定的方向键编辑单独行,也可以回到之前的命令行再执行或编辑它,就如同 shell 命令一样。

irb 是一个非常好的学习工具,如果你想快速验证一个想法并看到它运行,irb 是一个非常便捷的工具。

支持的编辑器

Ruby 被设计为一次读取一个程序,这意味着你可以传递一个完整的程序给 Ruby 的标准输入,它将正常运转。

我们在编辑器中运行 Ruby 代码时也会从这个特性获益。例如,在 Emacs 中,你可以选择一块 Ruby 字符并且用命令 Meta-| 运行它。Ruby 解释器会将选择区域作为标准输入,然后输出至叫做 「Shell Commad Output」的缓冲区。在编写这本书的时候这个特性让我们工作很顺手,比如可以选择一段中的几行代码并运行它们。

你还可以通过 vi 编辑器实现类似的功能,vi 编辑器中可以使用 「:!ruby」将运行输出替换程序字符,或者使用「:w !ruby」可以不受缓冲影响地显示输出。其他编辑器也有类似的特性。

当我们讨论这个主题时,也许是个好机会,我们可以了解该改造版中包含了一种用于 Emacs 的 Ruby 模式也就是 misc/Ruby-mode.el。在 vim 中也有一些语法高亮,jed 以及其他的编辑器也非常好用。可以查看 Ruby 的 FAQ 了解相应情况和可用性。

它不运行了!

你已经阅读了足够多的书籍,你也开始编写自己的 Ruby 程序,但是它无法运转。这里列举了常见的陷阱和其他的技巧。

  • 属性的设置方法无法正常调用。在对象中,Ruby 将 setter= 解析为对本地变量的赋值,并不会作为方法调用。需要通过 self.setter= 指明方法的调用。

  • 在源文件的最后一行解析报错说明缺少 end 关键字。

  • 确认使用对象的类型是否与认为的一致。如果有所怀疑,可以用 Object#type 检查对象的类型。

  • 确认你的方法是以小写字母开头,并且类和常量是以大写字母开头。

  • 如果你在参数列表中忘记写「,」,程序将会产生一些奇怪的错误信息。

  • 代码块参数是真实的局部变量。如果当代码块执行时已经存在一个同名的局部变量,此变量将被调用的代码块修改。这可能是件好事也可以成为一件坏事。

  • 需要当心优先级问题,特别是在使用 {} 替代 do/end 时。

  • 确认方法参数列表的左括号与方法名相连,中间不存在空格。

  • 输出到终端的信息可能进行缓冲区。这意味着你无法立即看见自己输出的信息。而且如果你通过 $stdout$stderr 输出信息,输出的内容可能不会按照你预期的顺序出现。如果是输出调试信息要使用无缓冲的 I/O (设置 sync=true)。

  • 如果关于数字的操作总是不正确,或许它们是字符串。从文件中读取的字符都是 String,在 Ruby 中也不会自动转换为数字。如果通过 to_i 调用后将正常运转。如果是 Perl 程序员可能就常会犯这样的错误。

while getsnum1, num2 = split /,/# ...
end
  • 计划外的混叠。如果你使用一个对象作为散列表的键,需要确认它不会修改到它的散列值(或者如果它会对列表值进行修改可以调用 Hash#rehash)。

  • 当变量值改变时通过 trace_var 查看。

  • 使用调试器。

  • 使用 Object#freeze。如果你怀疑一些未知的代码伪造了变量值,你可以尝试将变量冻结。在代码再次尝试对变量进行修改时将被捕捉到。

这是一些让你编写 Ruby 更加轻松愉悦的主要技巧。立即开发你的应用吧。写一些代码然后运行它们。再写一些,再运行它们。无类型语言的一个主要好处就是在你使用它们之前你不需要完善它们。

它太慢了!

Ruby 是可被解释的,高级的语言,这也意味着它不可能像低级别语言比如 C 语言那样执行速度快。这部分我们会学习一些提升性能的基本知识,或者你也可以查看 Performance 索引下的其他知识点。

创建本地边界封锁

在代码块执行前试图通过代码块定义变量。当遍历大量元素时你可以预声明迭代器变量提高执行速率。在下面的第一个例子中,Ruby 必须在每次迭代中创建新的 x 和 y 变量,但第二个版本中并不是这样做的。我们可以用 Ruby Application Archive 中的 benchmark 包比较循环:

require "benchmark"
include Benchmark
n = 1000000
bm(12) do |test|test.report("normal:")    don.times do |x|y = x + 1endendtest.report("predefine:") dox = y = 0n.times do |x|y = x + 1endend
end

结果是:

                  user     system      total        real
normal:       2.450000   0.020000   2.470000 (  2.468109)
predefine:    2.140000   0.020000   2.160000 (  2.155307)

使用分析器

Ruby 也自带代码分析器(详情可从 454 页开始查看)。自带代码分析器本身并没有什么让人惊讶的,但如果你了解到它是由 50 行 Ruby 代码编写而成时,你会感叹这是多么让人惊叹的语言呀。

你可以在通过命令行参数 -r profile 或在代码中加入 require "profile" 向代码添加分析器。例如:

require "profile"
class Peterdef initialize(amt)@value = amtenddef rob(amt)@value -= amtamtend
endclass Pauldef initialize@value = 0enddef pay(amt)@value += amtamtend
endpeter = Peter.new(1000)
paul = Paul.new
1000.times dopaul.pay(peter.rob(10))
end

运行这段代码你将获得如下的结果:

time   seconds   seconds    calls  ms/call  ms/call  name32.14     0.27      0.27        1   270.00   840.00  Fixnum#times30.95     0.53      0.26     1000     0.26     0.27  Paul#pay29.76     0.78      0.25     1000     0.25     0.30  Peter#rob5.95     0.83      0.05     1000     0.05     0.05  Fixnum#-1.19     0.84      0.01     1000     0.01     0.01  Fixnum#+0.00     0.84      0.00        1     0.00     0.00  Paul#initialize0.00     0.84      0.00        2     0.00     0.00  Class#inherited0.00     0.84      0.00        4     0.00     0.00  Module#method_added0.00     0.84      0.00        1     0.00     0.00  Peter#initialize0.00     0.84      0.00        1     0.00   840.00  #toplevel0.00     0.84      0.00        2     0.00     0.00  Class#new

使用分析器我们可以快速定位和修复瓶颈。记住在检查代码时不要使用分析器,由于分析器会将速度降低导致掩盖其他问题。

Ruby 是一种透明度高且表达力强的语言,但它并不能解决程序员使用其他语言的通病,比如创建不需要的对象,执行不需要的过程,以及编写臃肿的代码。

调试命令

CommandComment
b[reak] [file:]lineSet breakpoint at given line in file (default current file).
b[reak] [file:]nameSet breakpoint at method in file.
b[reak]Display breakpoints and watchpoints.
wat[ch] exprBreak when expression becomes true.
del[ete] [nnn]Delete breakpoint nnn (default all).
disp[lay] exprDisplay value of nnn every time debugger gets control.
disp[lay]Show current displays.
undisp[lay] [nnn]Remove display (default all).
c[ont]Continue execution.
s[tep] nnn=1Execute next nnn lines, stepping into methods.
n[ext] nnn=1Execute next nnn lines, stepping over methods.
fi[nish]Finish execution of the current function.
q[uit]Exit the debugger.
w[here]Display current stack frame.
f[rame]Synonym for where.
l[ist] [start–end]List source lines from start to end.
up nnn=1Move up nnn levels in the stack frame.
down nnn=1Move down nnn levels in the stack frame.
v[ar] g[lobal]Display global variables.
v[ar] l[ocal]Display local variables.
v[ar] i[stance] objDisplay instance variables of obj.
v[ar] c[onst] NameDisplay constants in class or module name.
m[ethod] i[nstance] objDisplay instance methods of obj.
m[ethod] NameDisplay instance methods of the class or module name.
th[read] l[ist]List all threads.
th[read] [c[ur[rent]]]Display status of current thread.
th[read] [c[ur[rent]]] nnnMake thread nnn current and stop it.
th[read] stop nnnMake thread nnn current and stop it.
th[read] resume nnnResume thread nnn.
[p] exprEvaluate expr in the current context. expr may include assignment to variables and method invocations.
emptyA null command repeats the last command.

本文翻译自《Programming Ruby》,主要目的是自己学习使用,文中翻译不到位之处烦请指正,如需转载请注明出处

本章原文为 When Trouble Strikes

这篇关于When Trouble Strikes的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1044819

相关文章

CSU - 1556 Jerry's trouble(快速幂取模)

【题目链接】:click here 【题目大意】:计算x1^m+x2^m+..xn^m(1<=x1<=n)( 1 <= n < 1 000 000, 1 <= m < 1000) 【解题思路】:快速幂取模 代码: solution one: #include<bits/stdc++.h>#define LL long longusing namespace std;const

[HDU 4334] Trouble (分治+二分查找)

HDU - 4334 给你五个数组,每组 N个元素 (N<=200) 问是否能在五个数组里各选一个数,使得和为0 思路是分治,然后再二分查找,降低复杂度 1) 算出 S1 S_1和 S2 S_2所有元素的和的情况并排序,对 S3 S_3和 S4 S_4亦是如此 O( N2 N^2) 2) 枚举 S3 S_3和 S4 S_4的和数组与 S5 S_5的和的情况 再在 S1 S

UVA 10497 - Sweet Child Makes Trouble(DP+高精度)

题目链接:10497 - Sweet Child Makes Trouble 题意:n个物品,原来物品属于一个地方,现在要把物品重新放回去,问能放几种使得每个物品都与原来位置不同 思路:递推,一开始随便搞了个二维状态,dp[i][j]表示i个物品,有j个位置不同,那么dp[n][n]就是答案,递推式为: dp[i][j] = 1 (j == 0) dp[i] [j]

Codeforces Round 928 (Div. 4) G. Vlad and Trouble at MIT 题解 树形dp

Vlad and Trouble at MIT 题目描述 弗拉迪斯拉夫有个儿子非常想去麻省理工学院。麻省理工学院(摩尔多瓦理工学院)的学生宿舍可以用一棵树来表示,树上有 n n n 个顶点,每个顶点代表一个房间,房间里正好有一个学生。树是一个连通的无向图,有 n n n 个顶点和 n − 1 n-1 n−1 条边。 今晚,有三种类型的学生: 想参加派对和玩音乐的学生(标记为 P \

LINUX QMAIL 451 qq trouble creating files in queue (#4.3.0) 的解决

今天头脑发热,清理了一下/var/qmail/queue下的文件,事先没有想清楚,用了find rm。问题来了,先是发送没有总是,但是收不到,后来干脆把第二级目录下的目录也删除了,直接提示451 qq trouble creating files in queue (#4.3.0)。完了!   GOOGLE了一下,发现那些目录是不能删的!只有重新make setup check,find一下,二级

ReLU Strikes Back: Exploiting Activation Sparsity in Large Language Models

iclr 2024 oral reviewer 评分 688 1 intro 目前LLM社区中通常使用GELU和SiLU来作为替代激活函数,它们在某些情况下可以提高LLM的预测准确率 但从节省模型计算量的角度考虑,论文认为经典的ReLU函数对模型收敛和性能的影响可以忽略不计,同时可以显着减少计算和权重IO量\ ​​​​​​​ 2 激活函数影响效果吗? 选用了开源的大模型 OPT,Llama

There appears to be trouble with your network connection. Retrying

一直在报如上错误,试了很多办法,比如删掉yarn.lock,yarn cache clean,删掉node_modules,rm proxy等等都没有用 甚至于重启电脑,然而并没有什么用 突然间想到,我用了clash for window 所以想了下,应该要设置proxy 先查电脑的ip cmd --> ipconfig 然后设置proxy yarn config set proxy

CF 780 D. Maximum Product Strikes Back

Problem - D - Codeforces 题目大意:找到一个连续的区间,此区间乘积最大,区间长度0时答案为1,输出区间左边删除数量和右边删除的数量。直接输出区间不好吗??? 解题思路:查询序列最大子段乘积,且答案至少是1,换句话说这个区间一定不包含0。 (1)先暴力思考解法,可以枚举区间左右端点[l,r]求得最大乘积,如果是正常数组,这个乘积必然超出整数范围,题目贴心地告知绝对值

info There appears to be trouble with your network connection. Retrying...

问题 安装依赖yarn install或npm i 时,如果遇到提示 info There appears to be trouble with your network connection. Retrying... 解决办法 删除yarn.lock或package-lock.json 文件,重新执行yarn install或npm i 就可以了

globus安装经验之trouble-shooting

添加用户guser1000globus1001condor1002find / -name 'filename' -print    查找文件名为filename的文件并打印其完整路径root下passwd username可以为新用户设定密码星空互联,文件挖掘者rm -rf muluCAhash:eefa0689uname -a    注意:Ixxx的全是32位的,有X86—64的全是64位Li