简体   繁体   English

Ruby - 清除所有全局变量

[英]Ruby - Clear all the global variables

I am using an existing framework for parallel execution.我正在使用现有的框架进行并行执行。 There are so many global variables being used in this.这里使用了很多全局变量。 I could see some of the global variables (yes, we should avoid it, but in this case, I don't have an option) are creating issues.我可以看到一些全局变量(是的,我们应该避免它,但在这种情况下,我没有选择)正在产生问题。 global_variables shows the list of all the global variables used. global_variables显示所有使用的全局变量的列表。 I want to clear them at the end of every execution.我想在每次执行结束时清除它们。 Any suggestions, please?请问有什么建议吗? (( ((

TL;DR TL;博士

You don't want to clear all globals, as Ruby depends on a number of global variables and constants for proper operation.您不想清除所有全局变量,因为 Ruby 依赖于许多全局变量和常量才能正常运行。 It's okay to clear the ones you've defined, though.不过,可以清除您定义的那些。

However, you can't actually undefine globals, although you can certainly re-assign their values.但是,您实际上不能取消定义全局变量,尽管您当然可以重新分配它们的值。 Refactoring to namespaced or lexically-scoped variables should be a longer term objective, even if the suggestions below work for you now.重构命名空间或词法范围的变量应该是一个长期目标,即使下面的建议现在对你有用。 There are many options for passing bindings, values, configuration settings, and object references that don't rely on globals, and reducing variable scope is usually the right thing to do in most cases.传递绑定、值、配置设置和不依赖全局变量的对象引用有很多选项,在大多数情况下,减小变量范围通常是正确的做法。

That said, here are some suggestions that may help with your situation.也就是说,这里有一些建议可能对您的情况有所帮助。 I've also noted some edge cases that may or may not apply to your code, but that should be in the back of your mind when dealing with top-level bindings and global namespaces.我还注意到一些边缘情况可能适用于您的代码,也可能不适用于您的代码,但在处理顶级绑定和全局命名空间时,这些情况应该放在您的脑海中。

You Can't Undefine or Garbage-Collect Globals您不能取消定义或垃圾收集全局变量

By definition, global variables never go out of scope.根据定义,全局变量永远不会超出范围。 That also means the variables themselves can never be garbage-collected either.这也意味着变量本身也永远不能被垃圾收集。

Additionally, similarly to instance variables but unlike class or local variables, global variables are auto-vivified * as nil when referenced to prevent NameError.此外,与实例变量类似,但与类或局部变量不同,全局变量在引用时自动激活*nil ,以防止出现 NameError。 Even if you never actually define $foo , $foo == nil #=> true .即使你从未真正定义过$foo$foo == nil #=> true


* As a subtle distinction, defined? $foo #=> nil *作为一个微妙的区别, defined? $foo #=> nil defined? $foo #=> nil while $foo = nil; defined? $foo #=> "global-variable" defined? $foo #=> nil$foo = nil; defined? $foo #=> "global-variable" $foo = nil; defined? $foo #=> "global-variable" $foo = nil; defined? $foo #=> "global-variable" , but I don't think that has any practical bearing on your question. $foo = nil; defined? $foo #=> "global-variable" ,但我认为这对您的问题没有任何实际影响。


If your primary goal is just to "unset" the values of your globals, you can do something like:如果您的主要目标只是“取消设置”全局变量的值,您可以执行以下操作:

NILABLE_GLOBALS = %w[$foo $bar $baz]
NILABLE_GLOBALS.map { eval "#{_1} = nil" }

While the variables are all still technically defined, pragmatically they will respond similarly to being undefined, eg by being equal to nil .虽然变量在技术上仍然是定义的,但实际上它们会以类似的方式响应未定义,例如等于nil

Reducing Memory Consumed by Globals减少全局变量消耗的内存

This approach may also minimize the memory footprint of the globals by pointing them all to what amounts to a singleton object, eg the sole instance of NilClass.这种方法还可以通过将全局变量全部指向一个单例对象(例如 NilClass 的唯一实例)来最小化全局变量的内存占用。 This should reduce memory usage if the values previously stored in your globals are garbage collected when nothing references them any longer.如果以前存储在全局变量中的值在不再引用它们时被垃圾收集,这应该会减少内存使用量。 There are perhaps several edge cases, like frozen strings stored in the TOPLEVEL_BINDING, where I'm unsure if the values will truly lose all references and thus be garbage collected, but that's more of a memory management issue than a value assignment or object identity issue, and if memory were a primary concern you wouldn't be using globals in the first place.可能有几个边缘情况,比如存储在 TOPLEVEL_BINDING 中的冻结字符串,我不确定这些值是否真的会丢失所有引用并因此被垃圾收集,但这更多的是内存管理问题而不是值分配或对象身份问题,如果内存是主要问题,那么您一开始就不会使用全局变量。

So long as you aren't relying on defined?只要你不依赖defined? returning nil when the values are reset, this seems like your best option short of refactoring your code to use variables that can go out of scope.重置值时返回nil ,这似乎是您最好的选择,而不是重构代码以使用可能超出范围的变量。

Additional Caveats额外注意事项

If you're using a much older version of Ruby that can't garbage-collect Symbols, assign String objects to your globals when you can.如果您使用的是无法垃圾收集符号的旧版 Ruby,请尽可能将 String 对象分配给您的全局变量。 You might also disable frozen strings as a default if you find that they aren't being garbage collected even when no longer referenced.如果您发现即使不再引用它们也没有被垃圾收集,您也可以默认禁用冻结字符串。 You can inspect ObjectSpace after calling the GC module to look for unwanted Symbol and String objects if memory bloats excessively.如果内存过度膨胀,您可以在调用GC 模块后检查ObjectSpace以查找不需要的 Symbol 和 String 对象。 While these are unlikely to be real problems for you, at least you have a starting point if they are.虽然这些对你来说不太可能是真正的问题,但如果是的话,至少你有一个起点。

At some early point in your program, record the global variables that are provided by the Ruby interpreter itself and store that it in a constant:在您的程序的某个早期阶段,记录 Ruby 解释器本身提供的全局变量并将其存储在一个常量中:

OrigGlobalVars = global_variables

I don't think there is a way to undefine global variables, but you can set all the new ones created by your code to nil by doing this:我认为没有办法取消定义全局变量,但您可以通过执行以下操作将代码创建的所有新变量设置为nil

(global_variables - OrigGlobalVars).each { |g| eval "#{g} = nil" }

This certainly might break some code that uses the global variables, because the code might not be designed to gracefully handle the case where the variable is nil.这肯定会破坏一些使用全局变量的代码,因为代码可能没有被设计为优雅地处理变量为 nil 的情况。 But you can fix those cases as they come up.但是你可以在它们出现时修复它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM