- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我目前正在为 ruby 进行一些速度测试,我需要将一些文本文件解析为数值。由于速度慢,我想知道我的代码是否可以优化,或者 ruby 是否真的那么慢。正在从文件中读取代码,这些文件包含大约 1 000 000 行随机生成的行或数字,我只会显示几行,以便您知道正在读取的内容。我需要读取的文件名作为参数传递,coed 是单独的脚本(只是为了我自己清楚)。
首先我想解析一个简单的数字,输入格式如下:
type
number
type
number
...
我是这样做的:
incr = 1
File.open(ARGV[0], "r").each_line do |line|
incr += 1
if incr % 3 == 0
line.to_i
end
end
其次,我需要解析为单个列表,输入采用以下格式:
type
(1,2,3,...)
type
(1,2,3,...)
...
我是这样做的
incr = 1
File.open(ARGV[0], "r").each_line do |line|
incr += 1
if incr % 3 == 0
line.gsub("(","").gsub(")","").split(",").map{ |s| s.to_i}
end
end
最后我需要解析成列表的列表,输入采用这种格式:
type
((1,2,3,...),(1,2,3,...),(...))
type
((1,2,3,...),(1,2,3,...),(...))
...
我是这样做的:
incr = 1
File.open(ARGV[0], "r").each_line do |line|
incr += 1
if incr % 3 == 0
line.split("),(").map{ |s| s.gsub("(","").gsub(")","").split(",").map{ |s| s.to_i}}
end
end
我不需要显示任何结果,我只是进行速度测试,所以不需要输出。我确实检查了结果,代码本身似乎工作正常,它们只是出奇地慢,我想用 ruby 提供的最佳功能进行速度测试。我知道有几个我可以使用的速度测试,但为了我的目的,我需要建立我自己的。
我可以做些什么更好?如何优化这段代码?我哪里出错了,或者这已经是 ruby 所能做到的最好的了?提前感谢您的提示和想法。
最佳答案
在第一个中,而不是:
File.open(ARGV[0], "r").each_line do |line|
使用:
File.foreach(ARGV[0]) do |line|
而不是:
incr += 1
if incr % 3 == 0
使用:
if $. % 3 == 0
$.
是最后读取行的行号的魔法变量。
在第二个中,而不是:
line.gsub("(","").gsub(")","").split(",").map{ |s| s.to_i}
使用:
line.tr('()', '').split(',').map(&:to_i)
在第三个,而不是:
line.split("),(").map{ |s| s.gsub("(","").gsub(")","").split(",").map{ |s| s.to_i}}
使用:
line.scan(/(?:\d+,?)+/).map{ |s| s.split(',', 0).map(&:to_i) }
这条线是这样工作的:
line.scan(/(?:\d+,?)+/)
=> ["1,2,3,", "1,2,3,"]
line.scan(/(?:\d+,?)+/).map{ |s| s.split(',',0) }
=> [["1", "2", "3"], ["1", "2", "3"]]
line.scan(/(?:\d+,?)+/).map{ |s| s.split(',', 0).map(&:to_i) }
=> [[1, 2, 3], [1, 2, 3]]
我没有运行任何基准测试来比较速度,但变化应该也更快,因为 gsub
调用已经消失。我所做的更改不一定是最快的做事方式,它们是您自己代码的更优化版本。
尝试将 Ruby 的速度与其他语言进行比较需要了解完成每个步骤的最快方法,并基于该步骤的多个基准。它还意味着您在相同的硬件和操作系统上运行,并且您的语言都被编译为最高效的速度形式。语言会在内存使用与速度之间进行权衡,因此,虽然一种语言可能比另一种慢,但它的内存效率也可能更高。
此外,在生产环境中编码时,生成正确运行的代码的时间必须计入“哪个更快”的等式中。 C 非常快,但对于大多数问题,编写程序比 Ruby 花费的时间更长,因为 C 不像 Ruby 那样握住你的手。 C 代码需要一周的时间来编写和调试,而 Ruby 代码需要一个小时,哪个更快?只是需要考虑的事情。
在我读完之前,我没有通读@tadman 的回答和评论。使用:
map(&:to_i)
过去比:
map{ |s| s.to_i }
速度差异取决于您运行的 Ruby 版本。最初使用 &:
是在一些猴子补丁中实现的,但现在它已内置到 Ruby 中。当他们进行更改时,速度大大加快:
require 'benchmark'
foo = [*('1'..'1000')] * 1000
puts foo.size
N = 10
puts "N=#{N}"
puts RUBY_VERSION
puts
Benchmark.bm(6) do |x|
x.report('&:to_i') { N.times { foo.map(&:to_i) }}
x.report('to_i') { N.times { foo.map{ |s| s.to_i } }}
end
哪些输出:
1000000
N=10
2.0.0
user system total real
&:to_i 1.240000 0.000000 1.240000 ( 1.250948)
to_i 1.400000 0.000000 1.400000 ( 1.410763)
这要经过 10,000,000 个元素,这只会导致 0.2/秒的差异。做同一件事的两种方法之间没有太大区别。如果您要处理更多数据,那么它很重要。对于大多数应用程序来说,这是一个有争议的问题,因为其他因素会成为瓶颈/减速,因此请以适合您的方式编写代码,并牢记速度差异。
为了显示 Ruby 版本的不同,这里是使用 Ruby 1.8.7 的相同基准测试结果:
1000000N=101.8.7 user system total real&:to_i 4.940000 0.000000 4.940000 ( 4.945604)to_i 2.390000 0.000000 2.390000 ( 2.396693)
As far as gsub
vs. tr
:
require 'benchmark'
foo = '()' * 500000
puts foo.size
N = 10
puts "N=#{N}"
puts RUBY_VERSION
puts
Benchmark.bm(6) do |x|
x.report('tr') { N.times { foo.tr('()', '') }}
x.report('gsub') { N.times { foo.gsub(/[()]/, '') }}
end
有了这些结果:
1000000N=101.8.7 user system total realtr 0.010000 0.000000 0.010000 ( 0.011652)gsub 3.010000 0.000000 3.010000 ( 3.014059)
and:
1000000N=102.0.0 user system total realtr 0.020000 0.000000 0.020000 ( 0.017230)gsub 1.900000 0.000000 1.900000 ( 1.904083)
Here's the sort of difference we can see from changing the regex pattern, which forces changes in the processing needed to get the desired result:
require 'benchmark'
line = '((1,2,3),(1,2,3))'
pattern1 = /\([\d,]+\)/
pattern2 = /\(([\d,]+)\)/
pattern3 = /\((?:\d+,?)+\)/
pattern4 = /\d(?:[\d,])+/
line.scan(pattern1) # => ["(1,2,3)", "(1,2,3)"]
line.scan(pattern2) # => [["1,2,3"], ["1,2,3"]]
line.scan(pattern3) # => ["(1,2,3)", "(1,2,3)"]
line.scan(pattern4) # => ["1,2,3", "1,2,3"]
line.scan(pattern1).map{ |s| s[1..-1].split(',').map(&:to_i) } # => [[1, 2, 3], [1, 2, 3]]
line.scan(pattern2).map{ |s| s[0].split(',').map(&:to_i) } # => [[1, 2, 3], [1, 2, 3]]
line.scan(pattern3).map{ |s| s[1..-1].split(',').map(&:to_i) } # => [[1, 2, 3], [1, 2, 3]]
line.scan(pattern4).map{ |s| s.split(',').map(&:to_i) } # => [[1, 2, 3], [1, 2, 3]]
N = 1000000
Benchmark.bm(8) do |x|
x.report('pattern1') { N.times { line.scan(pattern1).map{ |s| s[1..-1].split(',').map(&:to_i) } }}
x.report('pattern2') { N.times { line.scan(pattern2).map{ |s| s[0].split(',').map(&:to_i) } }}
x.report('pattern3') { N.times { line.scan(pattern3).map{ |s| s[1..-1].split(',').map(&:to_i) } }}
x.report('pattern4') { N.times { line.scan(pattern4).map{ |s| s.split(',').map(&:to_i) } }}
end
在 Ruby 2.0-p427 上:
user system total real
pattern1 5.610000 0.010000 5.620000 ( 5.606556)
pattern2 5.460000 0.000000 5.460000 ( 5.467228)
pattern3 5.730000 0.000000 5.730000 ( 5.731310)
pattern4 5.080000 0.010000 5.090000 ( 5.085965)
关于ruby - 优化用于将字符串解析为数值的 ruby 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17860692/
以下是一个非常简单的ruby服务器。 require 'socket' local_socket = Socket.new(:INET, :STREAM) local_addr = Socket.
我正在使用 OS X(使用 bash),并且是 unix 的新手。我想知道是否可以修改一些文件以便运行 ruby 程序,我不需要“ruby file.rb”,而是可以运行“ruby.rb”。 有理
我在用 Ruby 替换字符串时遇到一些问题。 我的原文:人之所为不如兽之所为。 我想替换为:==What== human does is not like ==what== animal does.
我想在一个循环中从 Ruby 脚本做这样的事情: 写一个文件a.rb(每次迭代都会改变) 执行系统(ruby 'a.rb') a.rb 将带有结果的字符串写入文件“results” a.rb 完成并且
我的问题是尝试创建一个本地服务器,以便我可以理解由我的新团队开发的应用程序。我的问题是我使用的是 Ruby 2.3.3,而 Gemfile 需要 2.3.1。我无法编辑 Gemfile,因为我被告知很
我有一个使用 GLI 框架用 Ruby 编写的命令行实用程序。我想在我的主目录中配置我的命令行实用程序,使用 Ruby 本身作为 DSL 来处理它(类似于 Gemfile 或 Rakefile)。 我
我的 Rails 应用 Controller 中有这段代码: def delete object = model.datamapper_class.first(:sourced_id =>
我正在寻找的解析器应该: 对 Ruby 解析友好, 规则设计优雅, 产生用户友好的解析错误, 用户文档的数量应该比计算器示例多, UPD:允许在编写语法时省略可选的空格。 快速解析不是一个重要的特性。
我刚开始使用 Ruby,听说有一种“Ruby 方式”编码。除了 Ruby on Rails 之外,还有哪些项目适合学习并被认可且设计良好? 最佳答案 Prawn被明确地创建为不仅是一个该死的好 PDF
我知道之前有人问过类似的问题,但是我该如何构建一个无需在前面输入“ruby”就可以在终端中运行的 Ruby 文件呢? 这里的最终目标是创建一个命令行工具包类型的东西。现在,为了执行我希望用户能够执行的
例如哈希a是{:name=>'mike',:age=>27,:gender=>'male'}哈希 b 是 {:name=>'mike'} 我想知道是否有更好的方法来判断 b 哈希是否在 a 哈希内,而
我是一名决定学习 Ruby 和 Ruby on Rails 的 ASP.NET MVC 开发人员。我已经有所了解并在 RoR 上创建了一个网站。在 ASP.NET MVC 上开发,我一直使用三层架构:
最近我看到 Gary Bernhardt 展示了他用来在 vim 中执行 Ruby 代码的 vim 快捷方式。捷径是 :map ,t :w\|:!ruby %. 似乎这个方法总是执行系统 Rub
在为 this question about Blue Ruby 选择的答案中,查克说: All of the current Ruby implementations are compiled to
我有一个 Ruby 数组 > list = Request.find_all_by_artist("Metallica").map(&:song) => ["Nothing else Matters"
我在四舍五入时遇到问题。我有一个 float ,我想将其四舍五入到小数点后的百分之一。但是,我只能使用 .round ,它基本上将它变成一个 int,意思是 2.34.round # => 2. 有没
我使用 ruby on rails 编写了一个小型 Web 应用程序,它的主要目的是上传、存储和显示来自 xml(文件最多几 MB)文件的结果。运行大约 2 个月后,我注意到 mongrel 进程
我们如何用 Ruby 转换像这样的字符串: 𝑙𝑎𝑡𝑜𝑟𝑟𝑒 收件人: Latorre 最佳答案 s = "𝑙𝑎𝑡𝑜𝑟𝑟𝑒" => "𝑙𝑎𝑡𝑜𝑟𝑟𝑒" s.u
通过 ruby monk 时,他们偶尔会从左侧字段中抛出一段语法不熟悉的代码: def compute(xyz) return nil unless xyz xyz.map {|a,
不确定我做错了什么,但我似乎弄错了。 问题是,给你一串空格分隔的数字,你必须返回最大和最小的数字。 注意:所有数字都是有效的 Int32,不需要验证它们。输入字符串中始终至少有一个数字。输出字符串必须
我是一名优秀的程序员,十分优秀!