ractorize 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +52 -4
- data/src/ractorize/ractorized_object.rb +18 -29
- data/src/ractorize.rb +5 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 259d8a0f04fdab353871748575089e83199cfad7d81440d4e6f3a957366c9301
|
|
4
|
+
data.tar.gz: e05e67142fdd2c081ec6baf244df8f7dadf991437c12e7d27cc87c793c863956
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ebd8a74f6bd6040740c5d41adb81f4caba0508ec28f1025eedb8a2feef826f5f09d764535593d464d3355bebe64941138f5789c9792223df8fe095af7384d985
|
|
7
|
+
data.tar.gz: 30b2f4d65a70d7218b5e3d76b1f6c04f3cb0c784fe8cd639d53770705caa61163c5c84ba678cd725f8f19296c1c6d985c6310ff461dbade04015522f96a8b155
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## [0.0.2] - 2026-05-18
|
|
2
|
+
|
|
3
|
+
- Make sure ractorized objects are shareable. This requires them to be unusable after closing (or joining) them.
|
|
4
|
+
- Make sure methods don't collide with core methods: #join/#close -> #__join__/#__close__
|
|
5
|
+
|
|
1
6
|
## [0.0.1] - 2026-04-14
|
|
2
7
|
|
|
3
8
|
- Initial release
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Ractorize
|
|
2
2
|
|
|
3
|
-
Have an object you wish
|
|
3
|
+
Have an object you wish were a ractor but isn't? Well, this gem lets you ractorize it!
|
|
4
4
|
|
|
5
5
|
When you ractorize an object, you can just call the normal methods on the object as if it weren't a ractor.
|
|
6
6
|
These method calls will automatically be sent as messages to a different ractor where that
|
|
@@ -50,12 +50,12 @@ also ractorize individual objects with `Ractorize[some_object]`.
|
|
|
50
50
|
Notice how, whether it's ractorized or not, we can just use the same exact interface? Fun!
|
|
51
51
|
|
|
52
52
|
You can find a script that benchmarks these the ractorized versus non-ractorized
|
|
53
|
-
approach in `example_scripts/product-
|
|
53
|
+
approach in `example_scripts/product-benchmark`.
|
|
54
54
|
|
|
55
|
-
Here's an example run of the product-
|
|
55
|
+
Here's an example run of the product-benchmark script:
|
|
56
56
|
|
|
57
57
|
```
|
|
58
|
-
$ example_scripts/product-
|
|
58
|
+
$ example_scripts/product-benchmark
|
|
59
59
|
benchmarking non-ractorized productizer
|
|
60
60
|
product is 0.568147e51
|
|
61
61
|
took 2.303 seconds
|
|
@@ -68,6 +68,54 @@ took 0.195 seconds
|
|
|
68
68
|
$
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
## Gotchas
|
|
72
|
+
|
|
73
|
+
### Predicate methods not ending in "?" will always return truthy values!
|
|
74
|
+
If you try to use the return value of a ractorized object (or any instance of a ractorized class)
|
|
75
|
+
in a boolean expression, it will always be truthy!!
|
|
76
|
+
|
|
77
|
+
You need to instead call `#__value__` on it to force it into the real value. This will make it block, but
|
|
78
|
+
that's what you want anyways in such a situation.
|
|
79
|
+
|
|
80
|
+
Example:
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
class String
|
|
84
|
+
def is_empty = empty?
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
if Ractorize["asdf"].is_empty
|
|
88
|
+
puts "It's empty!"
|
|
89
|
+
else
|
|
90
|
+
puts "It's not empty!"
|
|
91
|
+
end
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This will incorrectly print out `It's empty!`! To make it work you can force it to block and wait
|
|
95
|
+
for the actual value and use the actual value with the `#__value__` method:
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
class String
|
|
99
|
+
def is_empty = empty?
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if Ractorize["asdf"].is_empty.__value__
|
|
103
|
+
puts "It's empty!"
|
|
104
|
+
else
|
|
105
|
+
puts "It's not empty!"
|
|
106
|
+
end
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
This will correctly print out `It's not empty!`.
|
|
110
|
+
|
|
111
|
+
### Calling a method on a closed ractorized object might result in a deadlock!
|
|
112
|
+
|
|
113
|
+
It will usually raise a `Ractor::CloseError` but once in a while it can deadlock.
|
|
114
|
+
|
|
115
|
+
Note that if you call either `#__close__` or `#__join__` on the object, then the underlying ractor will be closed.
|
|
116
|
+
|
|
117
|
+
An easy way to avoid the deadlock is just don't make any use of such an object after closing it.
|
|
118
|
+
|
|
71
119
|
## Fine print
|
|
72
120
|
|
|
73
121
|
Ractors are still experimental and so this gem is also still experimental.
|
|
@@ -3,45 +3,40 @@ require_relative "thunk"
|
|
|
3
3
|
|
|
4
4
|
module Ractorize
|
|
5
5
|
class RactorizedObject < BasicObject
|
|
6
|
-
# Putting this in a constant so we can get test coverage on it since not sure how to get coverage
|
|
7
|
-
# on something inside a ractor.
|
|
8
|
-
|
|
9
|
-
attr_accessor :__object__
|
|
10
|
-
|
|
11
6
|
def initialize(outside_object)
|
|
12
7
|
@ractor = ::Ractor.new(&RACTOR_PROC)
|
|
13
8
|
|
|
14
9
|
# It doesn't seem like we have a way to move the object into the ractor via its constructor so do
|
|
15
10
|
# it with #<< instead.
|
|
16
11
|
@ractor.<<(outside_object, move: true)
|
|
17
|
-
end
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
@__object__ = if Thunk === result
|
|
23
|
-
result.__value__
|
|
24
|
-
else
|
|
25
|
-
result
|
|
26
|
-
end
|
|
13
|
+
# Wow, this works! Scary?
|
|
14
|
+
::Object.instance_method(:freeze).bind(self).call
|
|
27
15
|
end
|
|
28
16
|
|
|
29
|
-
def
|
|
30
|
-
|
|
17
|
+
def __close__ = method_missing(:__close__)
|
|
18
|
+
|
|
19
|
+
def __join__
|
|
20
|
+
__close__
|
|
31
21
|
@ractor.join
|
|
32
22
|
self
|
|
33
23
|
end
|
|
34
24
|
|
|
35
25
|
def method_missing(method_name, *args, **opts)
|
|
36
|
-
|
|
26
|
+
if @ractor.default_port.closed?
|
|
27
|
+
::Kernel.raise ::Ractor::ClosedError,
|
|
28
|
+
"You already closed this Ractorized object! No more methods can be sent to it."
|
|
29
|
+
end
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
@__object__.__send__(method_name, *args, **opts)
|
|
40
|
-
else
|
|
41
|
-
return_port = ::Ractor::Port.new
|
|
31
|
+
return_port = ::Ractor::Port.new
|
|
42
32
|
|
|
43
|
-
|
|
33
|
+
@ractor << [method_name, args, opts, return_port]
|
|
44
34
|
|
|
35
|
+
# Let's assume the user would rather block on all predicate methods than
|
|
36
|
+
# incorrectly get a non-truthy value (thunk is always truthy even if it evaluates as nil/false)
|
|
37
|
+
if method_name.end_with?("?")
|
|
38
|
+
return_port.receive
|
|
39
|
+
else
|
|
45
40
|
Thunk.new(return_port)
|
|
46
41
|
end
|
|
47
42
|
end
|
|
@@ -56,13 +51,7 @@ module Ractorize
|
|
|
56
51
|
end
|
|
57
52
|
|
|
58
53
|
def respond_to_missing?(method_name, include_all = false)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if ::Ractorize::Thunk === value
|
|
62
|
-
value.__value__
|
|
63
|
-
else
|
|
64
|
-
value
|
|
65
|
-
end
|
|
54
|
+
method_missing(:respond_to?, method_name, include_all)
|
|
66
55
|
end
|
|
67
56
|
end
|
|
68
57
|
end
|
data/src/ractorize.rb
CHANGED
|
@@ -3,6 +3,8 @@ require_relative "ractorize/ractorized_object"
|
|
|
3
3
|
require_relative "ractorize/ractorized_class"
|
|
4
4
|
|
|
5
5
|
module Ractorize
|
|
6
|
+
# Putting this in a constant so we can get test coverage on it since not sure how to get coverage
|
|
7
|
+
# on something inside a ractor.
|
|
6
8
|
RACTOR_PROC = proc do
|
|
7
9
|
object = receive
|
|
8
10
|
|
|
@@ -10,7 +12,7 @@ module Ractorize
|
|
|
10
12
|
method_name, method_args, opts, return_port = receive
|
|
11
13
|
|
|
12
14
|
case method_name
|
|
13
|
-
when :
|
|
15
|
+
when :__close__
|
|
14
16
|
return_port.<<(object, move: true)
|
|
15
17
|
close
|
|
16
18
|
break
|
|
@@ -20,6 +22,8 @@ module Ractorize
|
|
|
20
22
|
return_port << value
|
|
21
23
|
end
|
|
22
24
|
end
|
|
25
|
+
|
|
26
|
+
object
|
|
23
27
|
end
|
|
24
28
|
|
|
25
29
|
class << self
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ractorize
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Miles Georgi
|
|
@@ -46,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
47
|
version: '0'
|
|
48
48
|
requirements: []
|
|
49
|
-
rubygems_version: 4.0.
|
|
49
|
+
rubygems_version: 4.0.10
|
|
50
50
|
specification_version: 4
|
|
51
51
|
summary: Turn objects into ractors with ease!
|
|
52
52
|
test_files: []
|