我有以下示例代码。我有一个Test
对象,数量为10,然后准备被销毁。我有一个类,它是这些对象数组的包装器。此类每帧使用update
方法,并遍历Test
个对象的数组并更新每个对象。如果当前对象已达到最大计数,则删除对该对象的引用,并且当迭代完成时,该数组将变为紧凑。
require 'benchmark'
class Test
def update
@counter ||= 0
@counter += 1
end
def destroy?
@counter > 10
end
def dispose
# dispose this object
end
end
class Tests
def initialize(number)
@data = []
number.times do
@data.push(Test.new)
end
end
def add_data(data)
@data.push(data)
end
def update
@data.each_with_index do |t, index|
t.update
if t.destroy?
t.dispose # need to dispose the sprite object in my realcode before delete ref.
@data[index] = nil
end
end.compact!
end
# this would be another attempt, which is a little bit faster
# but this wont work because in my case the objects I use are
# sprite objects which needs to be disposed like shown above
# before the reference is removed
def update_2
@data.each(&:update)
@data.delete_if{|obj| obj.destroy?}
end
end
iterations = 2000000
Benchmark.bm do |x|
x.report {Tests.new(iterations).update}
x.report {Tests.new(iterations).update_2}
end
一个问题是,如果添加了许多对象,这会导致性能变差。另一个问题是,每个帧,另一个对象可以通过add_data
方法添加。我想知道是否可以采用另一种方法来实现这一目标,以使其不会对性能造成太大影响。
修改的 我使用自定义库(http://rmvxace.wikia.com/wiki/RGSS),因此我编辑了上面的代码,以便更清楚地了解更多内容。但主要问题仍然是更新方法。
答案 0 :(得分:1)
我可以看到代码的一些性能问题,尽管其他人可能做得更好。
这就是我的想法:
此外,您的基准测试始终会创建一个对象并对其进行一次更新 - 这不是比较的最佳基础。
例如,您的update_2实际上会慢得多......您根本没有注意到基准测试。
我更新了你的update_2方法并添加了一个update_3方法,这个方法在新的基准测试中更快一些。
update_3方法需要对Test类进行调整,该类现在有一个名为update_or_destroy的新方法,对于update,返回true,对于destroy,返回false。
我还添加了一个初始化方法来减少延迟初始化效果(在我的测试过程中,它表明它是减少工作负载的有效方法)。
试试这个:
require 'benchmark'
class Test
def initialize
@counter ||= 0
end
def update
@counter += 1
end
def destroy?
@counter > 10
end
def dispose
# dispose this object
end
def update_or_destroy
update
if destroy?
dispose
false
else
true
end
end
end
class Tests
def initialize(number)
@data = []
number.times do
@data.push(Test.new)
end
end
def add_data(data)
@data.push(data)
end
def update
@data.each_with_index do |t, index|
t.update
if t.destroy?
t.dispose # need to dispose the sprite object in my realcode before delete ref.
@data[index] = nil
end
end.compact!
end
# this would be another attempt, which is a little bit faster
# but this wont work because in my case the objects I use are
# sprite objects which needs to be disposed like shown above
# before the reference is removed
def update_2_updated
# @data.each(&:update)
@data.delete_if{|obj| obj.update; obj.destroy?}
end
def update_3
@data.keep_if {|obj| obj.update_or_destroy}
end
end
iterations = 2000000
Benchmark.bm do |x|
x.report {Tests.new(iterations).update}
x.report {Tests.new(iterations).update_2_updated}
x.report {Tests.new(iterations).update_3}
end
#new benchmarks
iterations = 100000
test_object = Tests.new(iterations)
puts Benchmark.measure { iterations.times { test_object.update } }
test_object = Tests.new(iterations)
puts Benchmark.measure { iterations.times { test_object.update_2_updated } }
test_object = Tests.new(iterations)
puts Benchmark.measure { iterations.times { test_object.update_3 } }