Ruby Implementations Quiz
Test your knowledge of Ruby implementations including MRI, JRuby, TruffleRuby, and native integration techniques.
Quiz Instructions
- Choose the best answer for each question
- Click "Show Answer" to reveal the correct answer and explanation
- Try to answer before looking at the solution
- Each question focuses on practical implementation knowledge
Question 1: Global Interpreter Lock
Which statement about MRI's Global Interpreter Lock (GIL) is correct?
Show Answer
Answer: B) The GIL is released during I/O operations, allowing I/O concurrency
Explanation: While the GIL prevents true parallel execution of Ruby code across threads, it is released during I/O operations (file reads, network requests, etc.). This allows Ruby threads to achieve concurrency for I/O-bound operations, making MRI well-suited for web applications and other I/O-heavy workloads.
Question 2: JRuby Advantages
What is the primary advantage of JRuby over MRI for CPU-intensive applications?
Show Answer
Answer: B) No Global Interpreter Lock, enabling true parallel threading
Explanation: JRuby's biggest advantage for CPU-intensive applications is the absence of a Global Interpreter Lock. This allows multiple threads to execute Ruby code in parallel, potentially providing significant performance improvements for multi-threaded, CPU-bound workloads. However, this also means you need to be more careful about thread safety.
Question 3: TruffleRuby Characteristics
Which statement best describes TruffleRuby's performance characteristics?
Show Answer
Answer: C) Slow startup but can achieve exceptional peak performance after warmup
Explanation: TruffleRuby is designed for peak performance rather than quick startup. It requires a significant warmup period (often 30+ seconds) for the GraalVM JIT compiler to analyze and optimize the code. However, once warmed up, it can be 10-100x faster than MRI for optimizable code, making it ideal for long-running applications.
Question 4: Code Example
Consider this CPU-intensive Ruby code:
def fibonacci(n)
return n if n <= 1
fibonacci(n - 1) + fibonacci(n - 2)
end
threads = []
4.times do
threads << Thread.new { fibonacci(35) }
end
threads.each(&:join)
Which Ruby implementation would likely show the best performance improvement compared to running the same code sequentially?
Show Answer
Answer: B) JRuby
Explanation: This is a CPU-intensive, pure computation task that can benefit from parallel execution. JRuby would show the best improvement because it has no GIL and can truly run the four threads in parallel. MRI would be limited by the GIL, while TruffleRuby, despite its eventual speed, would need significant warmup time and the parallel execution benefit might not outweigh the startup cost for this short-running example.
Question 5: FFI vs C Extensions
When would you choose FFI over writing a C extension?
Show Answer
Answer: B) When you need cross-Ruby implementation compatibility
Explanation: FFI's main advantage is portability across Ruby implementations (MRI, JRuby, TruffleRuby, etc.). C extensions are typically MRI-specific and need to be rewritten for other implementations. FFI also provides better safety, easier development (no compilation step), and automatic memory management, though at the cost of some performance compared to direct C extensions.
Question 6: C Extension Memory Management
In a C extension, what's the correct way to ensure Ruby objects are not garbage collected while being used in C code?
typedef struct {
VALUE ruby_object;
int some_data;
} my_struct_t;
Show Answer
Answer: B) Call rb_gc_mark() on the ruby_object in a mark function
Explanation: When storing Ruby objects in C structures, you must provide a mark function that calls rb_gc_mark() on any Ruby VALUE fields. This tells the garbage collector that these objects are still referenced and should not be collected. The mark function is registered when defining the data type and is called during garbage collection cycles.
Question 7: TruffleRuby Native Images
What is the main benefit of compiling a TruffleRuby application to a native image?
Show Answer
Answer: B) Instant startup time and lower memory usage
Explanation: Native images trade peak performance for instant startup and lower memory usage. They eliminate JVM startup overhead and the warmup period, making them ideal for serverless functions, CLI tools, and containerized applications where fast startup is more important than peak performance. However, they can't perform runtime JIT optimization.
Question 8: Implementation Selection
You're building a Ruby-based data processing service that needs to:
- Process large datasets with heavy mathematical computations
- Run continuously for hours
- Use multiple CPU cores effectively
- Integrate with existing Java infrastructure
Which Ruby implementation would be the best choice?
Show Answer
Answer: B) JRuby for true threading and Java integration
Explanation: JRuby is the best choice here because it provides: 1) True multi-threading without GIL limitations, allowing effective use of multiple CPU cores, 2) Seamless integration with existing Java infrastructure, 3) Good performance for long-running processes due to JVM optimizations, and 4) Access to Java's excellent mathematical and data processing libraries. While TruffleRuby might achieve higher peak performance, the Java integration requirement makes JRuby the practical choice.
Question 9: FFI Memory Safety
Which FFI code pattern is the safest for memory management?
Show Answer
Answer: B) Block-based automatic cleanup
Explanation: Block-based allocation with FFI::MemoryPointer ensures automatic cleanup when the block exits, even if an exception occurs. This pattern prevents memory leaks and is exception-safe. Manual allocation (A) is error-prone and can leak memory if exceptions occur. Global storage (C) can lead to memory leaks and makes cleanup timing unclear. Relying on GC (D) is unreliable because GC timing is unpredictable.
Question 10: Performance Trade-offs
Which statement best describes the performance trade-offs between Ruby implementations?
Show Answer
Answer: B) MRI has the best startup time while TruffleRuby has the best peak performance
Explanation: This correctly captures the fundamental trade-off: MRI starts quickly and is immediately productive, making it ideal for short-lived scripts and development. TruffleRuby requires significant warmup time but can achieve exceptional performance for long-running, computation-heavy applications. JRuby falls in between, with moderate startup time but good steady-state performance and the advantage of true threading. The best choice depends on your specific use case and performance requirements.
Quiz Complete! 🎉
Great job working through the Ruby implementations quiz! You've covered:
Core Concepts:
- MRI's Global Interpreter Lock
- JRuby's true multi-threading
- TruffleRuby's performance characteristics
- Native image compilation
Native Integration:
- C extensions vs FFI trade-offs
- Memory management best practices
- Cross-platform compatibility
- Performance considerations
💡 Key Takeaway: The best Ruby implementation depends on your specific needs. Consider startup time, peak performance requirements, threading needs, ecosystem compatibility, and deployment constraints when making your choice.
Continue Learning
Ready to dive deeper into Ruby implementations and ecosystem topics?