rbs 3.9.4 → 4.1.1
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/.clang-format +75 -0
- data/.clangd +2 -0
- data/.dockerignore +37 -0
- data/.github/dependabot.yml +16 -14
- data/.github/workflows/bundle-update.yml +63 -0
- data/.github/workflows/c-check.yml +66 -0
- data/.github/workflows/comments.yml +5 -3
- data/.github/workflows/dependabot.yml +2 -2
- data/.github/workflows/jruby.yml +79 -0
- data/.github/workflows/release-gems.yml +164 -0
- data/.github/workflows/ruby.yml +84 -30
- data/.github/workflows/rust.yml +186 -0
- data/.github/workflows/truffleruby.yml +54 -0
- data/.github/workflows/typecheck.yml +5 -2
- data/.github/workflows/wasm.yml +55 -0
- data/.github/workflows/windows.yml +9 -3
- data/.gitignore +16 -0
- data/.rubocop.yml +2 -2
- data/CHANGELOG.md +430 -0
- data/Dockerfile.jruby +53 -0
- data/README.md +41 -4
- data/Rakefile +777 -60
- data/Steepfile +11 -0
- data/config.yml +660 -62
- data/core/array.rbs +541 -398
- data/core/basic_object.rbs +9 -8
- data/core/binding.rbs +0 -2
- data/core/builtin.rbs +9 -8
- data/core/class.rbs +11 -8
- data/core/comparable.rbs +55 -34
- data/core/complex.rbs +104 -78
- data/core/dir.rbs +61 -49
- data/core/encoding.rbs +12 -15
- data/core/enumerable.rbs +297 -196
- data/core/enumerator/arithmetic_sequence.rbs +70 -0
- data/core/enumerator/product.rbs +5 -5
- data/core/enumerator.rbs +91 -28
- data/core/errno.rbs +11 -2
- data/core/errors.rbs +58 -29
- data/core/exception.rbs +13 -13
- data/core/fiber.rbs +74 -54
- data/core/file.rbs +260 -1151
- data/core/file_constants.rbs +463 -0
- data/core/file_stat.rbs +534 -0
- data/core/file_test.rbs +3 -3
- data/core/float.rbs +257 -116
- data/core/gc.rbs +425 -281
- data/core/hash.rbs +1151 -829
- data/core/integer.rbs +156 -195
- data/core/io/buffer.rbs +53 -42
- data/core/io/wait.rbs +13 -35
- data/core/io.rbs +220 -154
- data/core/kernel.rbs +239 -163
- data/core/marshal.rbs +4 -4
- data/core/match_data.rbs +16 -14
- data/core/math.rbs +107 -66
- data/core/method.rbs +69 -33
- data/core/module.rbs +302 -150
- data/core/nil_class.rbs +7 -6
- data/core/numeric.rbs +77 -63
- data/core/object.rbs +9 -11
- data/core/object_space/weak_key_map.rbs +7 -7
- data/core/object_space.rbs +30 -23
- data/core/pathname.rbs +1312 -0
- data/core/proc.rbs +95 -58
- data/core/process.rbs +222 -202
- data/core/ractor.rbs +364 -518
- data/core/random.rbs +21 -3
- data/core/range.rbs +181 -79
- data/core/rational.rbs +60 -89
- data/core/rbs/ops.rbs +154 -0
- data/core/rbs/unnamed/argf.rbs +63 -56
- data/core/rbs/unnamed/env_class.rbs +19 -14
- data/core/rbs/unnamed/main_class.rbs +123 -0
- data/core/rbs/unnamed/random.rbs +11 -118
- data/core/regexp.rbs +258 -214
- data/core/ruby.rbs +53 -0
- data/core/ruby_vm.rbs +78 -34
- data/core/rubygems/config_file.rbs +5 -5
- data/core/rubygems/errors.rbs +6 -70
- data/core/rubygems/requirement.rbs +5 -15
- data/core/rubygems/rubygems.rbs +18 -81
- data/core/rubygems/specification.rbs +8 -0
- data/core/rubygems/version.rbs +2 -163
- data/core/set.rbs +493 -363
- data/core/signal.rbs +26 -16
- data/core/string.rbs +3234 -1285
- data/core/struct.rbs +43 -42
- data/core/symbol.rbs +41 -34
- data/core/thread.rbs +139 -83
- data/core/time.rbs +81 -50
- data/core/trace_point.rbs +41 -35
- data/core/true_class.rbs +2 -2
- data/core/unbound_method.rbs +24 -16
- data/core/warning.rbs +7 -7
- data/docs/CONTRIBUTING.md +2 -1
- data/docs/aliases.md +79 -0
- data/docs/collection.md +3 -3
- data/docs/config.md +171 -0
- data/docs/encoding.md +56 -0
- data/docs/gem.md +0 -1
- data/docs/inline.md +634 -0
- data/docs/rbs_by_example.md +20 -20
- data/docs/release.md +151 -0
- data/docs/rust.md +96 -0
- data/docs/sigs.md +3 -3
- data/docs/syntax.md +48 -18
- data/docs/type_fingerprint.md +21 -0
- data/docs/wasm_serialization.md +80 -0
- data/exe/rbs +1 -1
- data/ext/rbs_extension/ast_translation.c +1855 -0
- data/ext/rbs_extension/ast_translation.h +41 -0
- data/ext/rbs_extension/class_constants.c +187 -0
- data/{include/rbs/constants.h → ext/rbs_extension/class_constants.h} +23 -1
- data/ext/rbs_extension/compat.h +10 -0
- data/ext/rbs_extension/extconf.rb +26 -1
- data/ext/rbs_extension/legacy_location.c +299 -0
- data/ext/rbs_extension/legacy_location.h +82 -0
- data/ext/rbs_extension/main.c +603 -23
- data/ext/rbs_extension/rbs_extension.h +6 -21
- data/ext/rbs_extension/rbs_string_bridging.c +9 -0
- data/ext/rbs_extension/rbs_string_bridging.h +24 -0
- data/include/rbs/ast.h +1047 -0
- data/include/rbs/defines.h +99 -0
- data/include/rbs/lexer.h +207 -0
- data/include/rbs/location.h +40 -0
- data/include/rbs/parser.h +153 -0
- data/include/rbs/serialize.h +39 -0
- data/include/rbs/string.h +47 -0
- data/include/rbs/util/rbs_allocator.h +59 -0
- data/include/rbs/util/rbs_assert.h +20 -0
- data/include/rbs/util/rbs_buffer.h +83 -0
- data/include/rbs/util/rbs_constant_pool.h +6 -70
- data/include/rbs/util/rbs_encoding.h +282 -0
- data/include/rbs/util/rbs_unescape.h +24 -0
- data/include/rbs.h +9 -2
- data/lib/rbs/annotate/formatter.rb +3 -13
- data/lib/rbs/annotate/rdoc_annotator.rb +30 -32
- data/lib/rbs/annotate/rdoc_source.rb +1 -1
- data/lib/rbs/ast/annotation.rb +1 -1
- data/lib/rbs/ast/comment.rb +1 -1
- data/lib/rbs/ast/declarations.rb +10 -10
- data/lib/rbs/ast/members.rb +14 -14
- data/lib/rbs/ast/ruby/annotations.rb +451 -0
- data/lib/rbs/ast/ruby/comment_block.rb +247 -0
- data/lib/rbs/ast/ruby/declarations.rb +291 -0
- data/lib/rbs/ast/ruby/helpers/constant_helper.rb +28 -0
- data/lib/rbs/ast/ruby/helpers/location_helper.rb +15 -0
- data/lib/rbs/ast/ruby/members.rb +762 -0
- data/lib/rbs/ast/type_param.rb +24 -4
- data/lib/rbs/buffer.rb +142 -20
- data/lib/rbs/cli/diff.rb +16 -15
- data/lib/rbs/cli/validate.rb +63 -126
- data/lib/rbs/cli.rb +59 -29
- data/lib/rbs/collection/config/lockfile_generator.rb +28 -3
- data/lib/rbs/collection/sources/git.rb +7 -0
- data/lib/rbs/definition.rb +6 -1
- data/lib/rbs/definition_builder/ancestor_builder.rb +121 -65
- data/lib/rbs/definition_builder/method_builder.rb +74 -33
- data/lib/rbs/definition_builder.rb +177 -20
- data/lib/rbs/diff.rb +7 -1
- data/lib/rbs/environment/class_entry.rb +69 -0
- data/lib/rbs/environment/module_entry.rb +66 -0
- data/lib/rbs/environment.rb +410 -215
- data/lib/rbs/environment_loader.rb +2 -8
- data/lib/rbs/errors.rb +31 -21
- data/lib/rbs/inline_parser/comment_association.rb +117 -0
- data/lib/rbs/inline_parser.rb +568 -0
- data/lib/rbs/location_aux.rb +36 -4
- data/lib/rbs/locator.rb +5 -1
- data/lib/rbs/method_type.rb +5 -3
- data/lib/rbs/namespace.rb +47 -18
- data/lib/rbs/parser_aux.rb +37 -7
- data/lib/rbs/prototype/helpers.rb +57 -0
- data/lib/rbs/prototype/rb.rb +3 -28
- data/lib/rbs/prototype/rbi.rb +196 -45
- data/lib/rbs/prototype/runtime.rb +12 -2
- data/lib/rbs/resolver/constant_resolver.rb +2 -2
- data/lib/rbs/resolver/type_name_resolver.rb +120 -44
- data/lib/rbs/rewriter.rb +70 -0
- data/lib/rbs/source.rb +99 -0
- data/lib/rbs/subtractor.rb +7 -4
- data/lib/rbs/test/type_check.rb +25 -3
- data/lib/rbs/type_name.rb +34 -21
- data/lib/rbs/types.rb +91 -79
- data/lib/rbs/unit_test/convertibles.rb +1 -0
- data/lib/rbs/unit_test/type_assertions.rb +44 -8
- data/lib/rbs/validator.rb +2 -2
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs/wasm/deserializer.rb +213 -0
- data/lib/rbs/wasm/location.rb +61 -0
- data/lib/rbs/wasm/parser.rb +137 -0
- data/lib/rbs/wasm/runtime.rb +196 -0
- data/lib/rbs/wasm/serialization_schema.rb +110 -0
- data/lib/rbs.rb +25 -2
- data/lib/rbs_jars.rb +39 -0
- data/lib/rdoc/discover.rb +1 -1
- data/lib/rdoc_plugin/parser.rb +8 -3
- data/rbs.gemspec +37 -5
- data/schema/typeParam.json +17 -1
- data/sig/ancestor_builder.rbs +1 -1
- data/sig/annotate/formatter.rbs +2 -2
- data/sig/annotate/rdoc_annotater.rbs +13 -10
- data/sig/ast/ruby/annotations.rbs +470 -0
- data/sig/ast/ruby/comment_block.rbs +127 -0
- data/sig/ast/ruby/declarations.rbs +158 -0
- data/sig/ast/ruby/helpers/constant_helper.rbs +11 -0
- data/sig/ast/ruby/helpers/location_helper.rbs +15 -0
- data/sig/ast/ruby/members.rbs +198 -0
- data/sig/buffer.rbs +81 -5
- data/sig/cli/diff.rbs +5 -11
- data/sig/cli/validate.rbs +12 -8
- data/sig/cli.rbs +18 -18
- data/sig/collection/config/lockfile_generator.rbs +2 -0
- data/sig/definition.rbs +6 -0
- data/sig/definition_builder.rbs +3 -1
- data/sig/environment/class_entry.rbs +50 -0
- data/sig/environment/module_entry.rbs +50 -0
- data/sig/environment.rbs +94 -87
- data/sig/errors.rbs +26 -20
- data/sig/inline_parser/comment_association.rbs +71 -0
- data/sig/inline_parser.rbs +126 -0
- data/sig/location.rbs +32 -7
- data/sig/locator.rbs +0 -2
- data/sig/manifest.yaml +0 -2
- data/sig/method_builder.rbs +9 -4
- data/sig/namespace.rbs +20 -5
- data/sig/parser.rbs +77 -13
- data/sig/prototype/helpers.rbs +2 -0
- data/sig/prototype/rbi.rbs +33 -4
- data/sig/resolver/type_name_resolver.rbs +36 -10
- data/sig/rewriter.rbs +45 -0
- data/sig/source.rbs +48 -0
- data/sig/type_param.rbs +13 -8
- data/sig/typename.rbs +15 -5
- data/sig/types.rbs +10 -8
- data/sig/unit_test/spy.rbs +0 -8
- data/sig/unit_test/type_assertions.rbs +15 -0
- data/sig/wasm/deserializer.rbs +66 -0
- data/sig/wasm/serialization_schema.rbs +13 -0
- data/src/ast.c +1628 -0
- data/src/lexer.c +3221 -0
- data/src/lexer.re +155 -0
- data/src/lexstate.c +221 -0
- data/src/location.c +31 -0
- data/src/parser.c +4258 -0
- data/src/serialize.c +958 -0
- data/src/string.c +41 -0
- data/src/util/rbs_allocator.c +171 -0
- data/src/util/rbs_assert.c +19 -0
- data/src/util/rbs_buffer.c +54 -0
- data/src/util/rbs_constant_pool.c +18 -92
- data/src/util/rbs_encoding.c +21308 -0
- data/src/util/rbs_unescape.c +167 -0
- data/stdlib/abbrev/0/array.rbs +1 -1
- data/stdlib/bigdecimal/0/big_decimal.rbs +116 -98
- data/stdlib/bigdecimal-math/0/big_math.rbs +169 -8
- data/stdlib/cgi/0/core.rbs +9 -393
- data/stdlib/cgi/0/manifest.yaml +1 -0
- data/stdlib/cgi-escape/0/escape.rbs +171 -0
- data/stdlib/coverage/0/coverage.rbs +7 -4
- data/stdlib/csv/0/csv.rbs +5 -5
- data/stdlib/date/0/date.rbs +92 -79
- data/stdlib/date/0/date_time.rbs +25 -24
- data/stdlib/delegate/0/delegator.rbs +11 -7
- data/stdlib/did_you_mean/0/did_you_mean.rbs +17 -16
- data/stdlib/digest/0/digest.rbs +117 -1
- data/stdlib/erb/0/erb.rbs +748 -347
- data/stdlib/etc/0/etc.rbs +73 -54
- data/stdlib/fileutils/0/fileutils.rbs +179 -160
- data/stdlib/forwardable/0/forwardable.rbs +13 -10
- data/stdlib/io-console/0/io-console.rbs +2 -2
- data/stdlib/ipaddr/0/ipaddr.rbs +0 -5
- data/stdlib/json/0/json.rbs +232 -185
- data/stdlib/monitor/0/monitor.rbs +5 -5
- data/stdlib/net-http/0/net-http.rbs +162 -134
- data/stdlib/objspace/0/objspace.rbs +17 -34
- data/stdlib/open-uri/0/open-uri.rbs +48 -8
- data/stdlib/open3/0/open3.rbs +469 -10
- data/stdlib/openssl/0/openssl.rbs +521 -397
- data/stdlib/optparse/0/optparse.rbs +26 -17
- data/stdlib/pathname/0/pathname.rbs +11 -1381
- data/stdlib/pp/0/pp.rbs +9 -8
- data/stdlib/prettyprint/0/prettyprint.rbs +7 -7
- data/stdlib/pstore/0/pstore.rbs +35 -30
- data/stdlib/psych/0/psych.rbs +65 -12
- data/stdlib/psych/0/store.rbs +2 -4
- data/stdlib/pty/0/pty.rbs +9 -6
- data/stdlib/random-formatter/0/random-formatter.rbs +277 -0
- data/stdlib/rdoc/0/code_object.rbs +4 -3
- data/stdlib/rdoc/0/comment.rbs +2 -0
- data/stdlib/rdoc/0/options.rbs +76 -0
- data/stdlib/rdoc/0/parser.rbs +1 -1
- data/stdlib/rdoc/0/rdoc.rbs +7 -5
- data/stdlib/rdoc/0/store.rbs +2 -2
- data/stdlib/resolv/0/resolv.rbs +26 -69
- data/stdlib/ripper/0/ripper.rbs +25 -19
- data/stdlib/securerandom/0/manifest.yaml +2 -0
- data/stdlib/securerandom/0/securerandom.rbs +7 -20
- data/stdlib/shellwords/0/shellwords.rbs +3 -3
- data/stdlib/singleton/0/singleton.rbs +3 -0
- data/stdlib/socket/0/addrinfo.rbs +9 -9
- data/stdlib/socket/0/basic_socket.rbs +3 -3
- data/stdlib/socket/0/ip_socket.rbs +10 -8
- data/stdlib/socket/0/socket.rbs +23 -10
- data/stdlib/socket/0/tcp_server.rbs +1 -1
- data/stdlib/socket/0/tcp_socket.rbs +11 -3
- data/stdlib/socket/0/udp_socket.rbs +1 -1
- data/stdlib/socket/0/unix_server.rbs +1 -1
- data/stdlib/stringio/0/stringio.rbs +1209 -95
- data/stdlib/strscan/0/string_scanner.rbs +101 -80
- data/stdlib/tempfile/0/manifest.yaml +3 -0
- data/stdlib/tempfile/0/tempfile.rbs +25 -21
- data/stdlib/time/0/time.rbs +8 -6
- data/stdlib/timeout/0/timeout.rbs +58 -7
- data/stdlib/tsort/0/cyclic.rbs +4 -1
- data/stdlib/tsort/0/interfaces.rbs +8 -8
- data/stdlib/tsort/0/tsort.rbs +16 -15
- data/stdlib/uri/0/common.rbs +42 -20
- data/stdlib/uri/0/file.rbs +3 -3
- data/stdlib/uri/0/generic.rbs +21 -18
- data/stdlib/uri/0/http.rbs +2 -2
- data/stdlib/uri/0/ldap.rbs +2 -2
- data/stdlib/uri/0/mailto.rbs +3 -3
- data/stdlib/uri/0/rfc2396_parser.rbs +12 -12
- data/stdlib/zlib/0/deflate.rbs +4 -3
- data/stdlib/zlib/0/gzip_reader.rbs +8 -8
- data/stdlib/zlib/0/gzip_writer.rbs +14 -12
- data/stdlib/zlib/0/inflate.rbs +1 -1
- data/stdlib/zlib/0/need_dict.rbs +1 -1
- data/wasm/README.md +60 -0
- data/wasm/rbs_wasm.c +423 -0
- metadata +131 -19
- data/ext/rbs_extension/lexer.c +0 -2728
- data/ext/rbs_extension/lexer.h +0 -179
- data/ext/rbs_extension/lexer.re +0 -147
- data/ext/rbs_extension/lexstate.c +0 -175
- data/ext/rbs_extension/location.c +0 -325
- data/ext/rbs_extension/location.h +0 -85
- data/ext/rbs_extension/parser.c +0 -2982
- data/ext/rbs_extension/parser.h +0 -18
- data/ext/rbs_extension/parserstate.c +0 -411
- data/ext/rbs_extension/parserstate.h +0 -163
- data/ext/rbs_extension/unescape.c +0 -32
- data/include/rbs/ruby_objs.h +0 -72
- data/src/constants.c +0 -153
- data/src/ruby_objs.c +0 -799
data/core/ractor.rbs
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
# <!-- rdoc-file=ractor.rb -->
|
|
2
|
-
# Ractor
|
|
3
|
-
# parallel execution.
|
|
4
|
-
#
|
|
5
|
-
# Ractor.new makes a new Ractor, which can run in parallel.
|
|
2
|
+
# Ractor.new creates a new Ractor, which can run in parallel with other ractors.
|
|
6
3
|
#
|
|
7
4
|
# # The simplest ractor
|
|
8
5
|
# r = Ractor.new {puts "I am in Ractor!"}
|
|
9
|
-
# r.
|
|
6
|
+
# r.join # wait for it to finish
|
|
10
7
|
# # Here, "I am in Ractor!" is printed
|
|
11
8
|
#
|
|
12
9
|
# Ractors do not share all objects with each other. There are two main benefits
|
|
13
10
|
# to this: across ractors, thread-safety concerns such as data-races and
|
|
14
11
|
# race-conditions are not possible. The other benefit is parallelism.
|
|
15
12
|
#
|
|
16
|
-
# To achieve this, object sharing is limited across ractors.
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
13
|
+
# To achieve this, object sharing is limited across ractors. Unlike in threads,
|
|
14
|
+
# ractors can't access all the objects available in other ractors. For example,
|
|
15
|
+
# objects normally available through variables in the outer scope are prohibited
|
|
16
|
+
# from being used across ractors.
|
|
20
17
|
#
|
|
21
18
|
# a = 1
|
|
22
19
|
# r = Ractor.new {puts "I am in Ractor! a=#{a}"}
|
|
@@ -27,80 +24,37 @@
|
|
|
27
24
|
# a = 1
|
|
28
25
|
# r = Ractor.new(a) { |a1| puts "I am in Ractor! a=#{a1}"}
|
|
29
26
|
#
|
|
30
|
-
# On CRuby (the default implementation), Global Virtual Machine Lock (GVL)
|
|
31
|
-
# held per ractor, so ractors can
|
|
32
|
-
#
|
|
27
|
+
# On CRuby (the default implementation), the Global Virtual Machine Lock (GVL)
|
|
28
|
+
# is held per ractor, so ractors can run in parallel. This is unlike the
|
|
29
|
+
# situation with threads on CRuby.
|
|
33
30
|
#
|
|
34
31
|
# Instead of accessing shared state, objects should be passed to and from
|
|
35
32
|
# ractors by sending and receiving them as messages.
|
|
36
33
|
#
|
|
37
34
|
# a = 1
|
|
38
35
|
# r = Ractor.new do
|
|
39
|
-
# a_in_ractor = receive # receive blocks until
|
|
36
|
+
# a_in_ractor = receive # receive blocks the Thread until our default port gets sent a message
|
|
40
37
|
# puts "I am in Ractor! a=#{a_in_ractor}"
|
|
41
38
|
# end
|
|
42
39
|
# r.send(a) # pass it
|
|
43
|
-
# r.
|
|
40
|
+
# r.join
|
|
44
41
|
# # Here, "I am in Ractor! a=1" is printed
|
|
45
42
|
#
|
|
46
|
-
# There are two pairs of methods for sending/receiving messages:
|
|
47
|
-
#
|
|
48
|
-
# * Ractor#send and Ractor.receive for when the *sender* knows the receiver
|
|
49
|
-
# (push);
|
|
50
|
-
# * Ractor.yield and Ractor#take for when the *receiver* knows the sender
|
|
51
|
-
# (pull);
|
|
52
|
-
#
|
|
53
43
|
# In addition to that, any arguments passed to Ractor.new are passed to the
|
|
54
44
|
# block and available there as if received by Ractor.receive, and the last block
|
|
55
|
-
# value
|
|
56
|
-
#
|
|
57
|
-
# A little demonstration of a classic ping-pong:
|
|
58
|
-
#
|
|
59
|
-
# server = Ractor.new(name: "server") do
|
|
60
|
-
# puts "Server starts: #{self.inspect}"
|
|
61
|
-
# puts "Server sends: ping"
|
|
62
|
-
# Ractor.yield 'ping' # The server doesn't know the receiver and sends to whoever interested
|
|
63
|
-
# received = Ractor.receive # The server doesn't know the sender and receives from whoever sent
|
|
64
|
-
# puts "Server received: #{received}"
|
|
65
|
-
# end
|
|
66
|
-
#
|
|
67
|
-
# client = Ractor.new(server) do |srv| # The server is sent to the client, and available as srv
|
|
68
|
-
# puts "Client starts: #{self.inspect}"
|
|
69
|
-
# received = srv.take # The client takes a message from the server
|
|
70
|
-
# puts "Client received from " \
|
|
71
|
-
# "#{srv.inspect}: #{received}"
|
|
72
|
-
# puts "Client sends to " \
|
|
73
|
-
# "#{srv.inspect}: pong"
|
|
74
|
-
# srv.send 'pong' # The client sends a message to the server
|
|
75
|
-
# end
|
|
76
|
-
#
|
|
77
|
-
# [client, server].each(&:take) # Wait until they both finish
|
|
78
|
-
#
|
|
79
|
-
# This will output something like:
|
|
80
|
-
#
|
|
81
|
-
# Server starts: #<Ractor:#2 server test.rb:1 running>
|
|
82
|
-
# Server sends: ping
|
|
83
|
-
# Client starts: #<Ractor:#3 test.rb:8 running>
|
|
84
|
-
# Client received from #<Ractor:#2 server test.rb:1 blocking>: ping
|
|
85
|
-
# Client sends to #<Ractor:#2 server test.rb:1 blocking>: pong
|
|
86
|
-
# Server received: pong
|
|
87
|
-
#
|
|
88
|
-
# Ractors receive their messages via the *incoming port*, and send them to the
|
|
89
|
-
# *outgoing port*. Either one can be disabled with Ractor#close_incoming and
|
|
90
|
-
# Ractor#close_outgoing, respectively. When a ractor terminates, its ports are
|
|
91
|
-
# closed automatically.
|
|
45
|
+
# value can be received with Ractor#value.
|
|
92
46
|
#
|
|
93
47
|
# ## Shareable and unshareable objects
|
|
94
48
|
#
|
|
95
|
-
# When an object is sent to
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
#
|
|
49
|
+
# When an object is sent to a ractor, it's important to understand whether the
|
|
50
|
+
# object is shareable or unshareable. Most Ruby objects are unshareable objects.
|
|
51
|
+
# Even frozen objects can be unshareable if they contain (through their instance
|
|
52
|
+
# variables) unfrozen objects.
|
|
99
53
|
#
|
|
100
|
-
# Shareable objects are those which can be used by several
|
|
101
|
-
# compromising thread-safety, for example numbers, `true` and `false`.
|
|
54
|
+
# Shareable objects are those which can be used by several ractors at once
|
|
55
|
+
# without compromising thread-safety, for example numbers, `true` and `false`.
|
|
102
56
|
# Ractor.shareable? allows you to check this, and Ractor.make_shareable tries to
|
|
103
|
-
# make the object shareable if it's not already
|
|
57
|
+
# make the object shareable if it's not already and gives an error if it can't
|
|
104
58
|
# do it.
|
|
105
59
|
#
|
|
106
60
|
# Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are shareable
|
|
@@ -116,25 +70,25 @@
|
|
|
116
70
|
# ary[0].frozen? #=> true
|
|
117
71
|
# ary[1].frozen? #=> true
|
|
118
72
|
#
|
|
119
|
-
# When a shareable object is sent
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
# the
|
|
123
|
-
#
|
|
73
|
+
# When a shareable object is sent via #send, no additional processing occurs on
|
|
74
|
+
# it and it becomes usable by both ractors. When an unshareable object is sent,
|
|
75
|
+
# it can be either *copied* or *moved*. Copying is the default, and it copies
|
|
76
|
+
# the object fully by deep cloning (Object#clone) the non-shareable parts of its
|
|
77
|
+
# structure.
|
|
124
78
|
#
|
|
125
|
-
# data = ['foo', 'bar'.freeze]
|
|
79
|
+
# data = ['foo'.dup, 'bar'.freeze]
|
|
126
80
|
# r = Ractor.new do
|
|
127
81
|
# data2 = Ractor.receive
|
|
128
82
|
# puts "In ractor: #{data2.object_id}, #{data2[0].object_id}, #{data2[1].object_id}"
|
|
129
83
|
# end
|
|
130
84
|
# r.send(data)
|
|
131
|
-
# r.
|
|
85
|
+
# r.join
|
|
132
86
|
# puts "Outside : #{data.object_id}, #{data[0].object_id}, #{data[1].object_id}"
|
|
133
87
|
#
|
|
134
88
|
# This will output something like:
|
|
135
89
|
#
|
|
136
|
-
# In ractor:
|
|
137
|
-
# Outside :
|
|
90
|
+
# In ractor: 8, 16, 24
|
|
91
|
+
# Outside : 32, 40, 24
|
|
138
92
|
#
|
|
139
93
|
# Note that the object ids of the array and the non-frozen string inside the
|
|
140
94
|
# array have changed in the ractor because they are different objects. The
|
|
@@ -142,8 +96,9 @@
|
|
|
142
96
|
# object.
|
|
143
97
|
#
|
|
144
98
|
# Deep cloning of objects may be slow, and sometimes impossible. Alternatively,
|
|
145
|
-
#
|
|
146
|
-
# object to the receiving ractor, making it inaccessible to the
|
|
99
|
+
# <code>move: true</code> may be used during sending. This will *move* the
|
|
100
|
+
# unshareable object to the receiving ractor, making it inaccessible to the
|
|
101
|
+
# sending ractor.
|
|
147
102
|
#
|
|
148
103
|
# data = ['foo', 'bar']
|
|
149
104
|
# r = Ractor.new do
|
|
@@ -151,7 +106,7 @@
|
|
|
151
106
|
# puts "In ractor: #{data_in_ractor.object_id}, #{data_in_ractor[0].object_id}"
|
|
152
107
|
# end
|
|
153
108
|
# r.send(data, move: true)
|
|
154
|
-
# r.
|
|
109
|
+
# r.join
|
|
155
110
|
# puts "Outside: moved? #{Ractor::MovedObject === data}"
|
|
156
111
|
# puts "Outside: #{data.inspect}"
|
|
157
112
|
#
|
|
@@ -161,14 +116,14 @@
|
|
|
161
116
|
# Outside: moved? true
|
|
162
117
|
# test.rb:9:in `method_missing': can not send any methods to a moved object (Ractor::MovedError)
|
|
163
118
|
#
|
|
164
|
-
# Notice that even `inspect`
|
|
119
|
+
# Notice that even `inspect` and more basic methods like `__id__` are
|
|
165
120
|
# inaccessible on a moved object.
|
|
166
121
|
#
|
|
167
|
-
# Class and Module objects are shareable
|
|
168
|
-
# shared between ractors. Ractor objects are also shareable. All operations
|
|
169
|
-
# shareable objects are thread-safe
|
|
170
|
-
#
|
|
171
|
-
#
|
|
122
|
+
# `Class` and `Module` objects are shareable and their class/module definitions
|
|
123
|
+
# are shared between ractors. Ractor objects are also shareable. All operations
|
|
124
|
+
# on shareable objects are thread-safe across ractors. Defining mutable,
|
|
125
|
+
# shareable objects in Ruby is not possible, but C extensions can introduce
|
|
126
|
+
# them.
|
|
172
127
|
#
|
|
173
128
|
# It is prohibited to access (get) instance variables of shareable objects in
|
|
174
129
|
# other ractors if the values of the variables aren't shareable. This can occur
|
|
@@ -189,7 +144,7 @@
|
|
|
189
144
|
# puts "I can't see #{cls.tricky}"
|
|
190
145
|
# cls.tricky = true # doesn't get here, but this would also raise an error
|
|
191
146
|
# end
|
|
192
|
-
# r.
|
|
147
|
+
# r.join
|
|
193
148
|
# # I see C
|
|
194
149
|
# # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
|
|
195
150
|
#
|
|
@@ -203,7 +158,7 @@
|
|
|
203
158
|
# puts "GOOD=#{GOOD}"
|
|
204
159
|
# puts "BAD=#{BAD}"
|
|
205
160
|
# end
|
|
206
|
-
# r.
|
|
161
|
+
# r.join
|
|
207
162
|
# # GOOD=good
|
|
208
163
|
# # can not access non-shareable objects in constant Object::BAD by non-main Ractor. (NameError)
|
|
209
164
|
#
|
|
@@ -213,12 +168,12 @@
|
|
|
213
168
|
# puts "I see #{C}"
|
|
214
169
|
# puts "I can't see #{C.tricky}"
|
|
215
170
|
# end
|
|
216
|
-
# r.
|
|
171
|
+
# r.join
|
|
217
172
|
# # I see C
|
|
218
173
|
# # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
|
|
219
174
|
#
|
|
220
|
-
# See also the description of
|
|
221
|
-
# syntax](rdoc-ref:syntax/comments.rdoc) explanation.
|
|
175
|
+
# See also the description of <code># shareable_constant_value</code> pragma in
|
|
176
|
+
# [Comments syntax](rdoc-ref:syntax/comments.rdoc) explanation.
|
|
222
177
|
#
|
|
223
178
|
# ## Ractors vs threads
|
|
224
179
|
#
|
|
@@ -229,20 +184,21 @@
|
|
|
229
184
|
# a = 1
|
|
230
185
|
# Thread.new {puts "Thread in ractor: a=#{a}"}.join
|
|
231
186
|
# end
|
|
232
|
-
# r.
|
|
187
|
+
# r.join
|
|
233
188
|
# # Here "Thread in ractor: a=1" will be printed
|
|
234
189
|
#
|
|
235
190
|
# ## Note on code examples
|
|
236
191
|
#
|
|
237
192
|
# In the examples below, sometimes we use the following method to wait for
|
|
238
|
-
# ractors
|
|
193
|
+
# ractors to make progress or finish.
|
|
239
194
|
#
|
|
240
195
|
# def wait
|
|
241
196
|
# sleep(0.1)
|
|
242
197
|
# end
|
|
243
198
|
#
|
|
244
|
-
#
|
|
245
|
-
# code. Most of the time, #
|
|
199
|
+
# This is **only for demonstration purposes** and shouldn't be used in a real
|
|
200
|
+
# code. Most of the time, #join is used to wait for ractors to finish and
|
|
201
|
+
# Ractor.receive is used to wait for messages.
|
|
246
202
|
#
|
|
247
203
|
# ## Reference
|
|
248
204
|
#
|
|
@@ -261,7 +217,7 @@ class Ractor
|
|
|
261
217
|
# rdoc-file=ractor.rb
|
|
262
218
|
# - [](sym)
|
|
263
219
|
# -->
|
|
264
|
-
#
|
|
220
|
+
# Gets a value from ractor-local storage for the current Ractor.
|
|
265
221
|
#
|
|
266
222
|
def self.[]: (Symbol) -> untyped
|
|
267
223
|
|
|
@@ -269,7 +225,7 @@ class Ractor
|
|
|
269
225
|
# rdoc-file=ractor.rb
|
|
270
226
|
# - []=(sym, val)
|
|
271
227
|
# -->
|
|
272
|
-
#
|
|
228
|
+
# Sets a value in ractor-local storage for the current Ractor.
|
|
273
229
|
#
|
|
274
230
|
def self.[]=: (Symbol, untyped) -> untyped
|
|
275
231
|
|
|
@@ -277,13 +233,13 @@ class Ractor
|
|
|
277
233
|
# rdoc-file=ractor.rb
|
|
278
234
|
# - count()
|
|
279
235
|
# -->
|
|
280
|
-
# Returns the number of
|
|
236
|
+
# Returns the number of ractors currently running or blocking (waiting).
|
|
281
237
|
#
|
|
282
238
|
# Ractor.count #=> 1
|
|
283
|
-
# r = Ractor.new(name: 'example') { Ractor.
|
|
239
|
+
# r = Ractor.new(name: 'example') { Ractor.receive }
|
|
284
240
|
# Ractor.count #=> 2 (main + example ractor)
|
|
285
|
-
# r
|
|
286
|
-
# r.
|
|
241
|
+
# r << 42 # r's Ractor.receive will resume
|
|
242
|
+
# r.join # wait for r's termination
|
|
287
243
|
# Ractor.count #=> 1
|
|
288
244
|
#
|
|
289
245
|
def self.count: () -> Integer
|
|
@@ -302,7 +258,7 @@ class Ractor
|
|
|
302
258
|
# rdoc-file=ractor.rb
|
|
303
259
|
# - main()
|
|
304
260
|
# -->
|
|
305
|
-
#
|
|
261
|
+
# Returns the main ractor.
|
|
306
262
|
#
|
|
307
263
|
def self.main: () -> Ractor
|
|
308
264
|
|
|
@@ -310,7 +266,7 @@ class Ractor
|
|
|
310
266
|
# rdoc-file=ractor.rb
|
|
311
267
|
# - main?()
|
|
312
268
|
# -->
|
|
313
|
-
#
|
|
269
|
+
# Returns true if the current ractor is the main ractor.
|
|
314
270
|
#
|
|
315
271
|
def self.main?: () -> boolish
|
|
316
272
|
|
|
@@ -318,7 +274,7 @@ class Ractor
|
|
|
318
274
|
# rdoc-file=ractor.rb
|
|
319
275
|
# - Ractor.make_shareable(obj, copy: false) -> shareable_obj
|
|
320
276
|
# -->
|
|
321
|
-
#
|
|
277
|
+
# Makes `obj` shareable between ractors.
|
|
322
278
|
#
|
|
323
279
|
# `obj` and all the objects it refers to will be frozen, unless they are already
|
|
324
280
|
# shareable.
|
|
@@ -357,13 +313,13 @@ class Ractor
|
|
|
357
313
|
# rdoc-file=ractor.rb
|
|
358
314
|
# - Ractor.new(*args, name: nil) {|*args| block } -> ractor
|
|
359
315
|
# -->
|
|
360
|
-
#
|
|
316
|
+
# Creates a new Ractor with args and a block.
|
|
361
317
|
#
|
|
362
|
-
# The given block (Proc)
|
|
363
|
-
#
|
|
318
|
+
# The given block (Proc) is isolated (can't access any outer variables). `self`
|
|
319
|
+
# inside the block will refer to the current Ractor.
|
|
364
320
|
#
|
|
365
321
|
# r = Ractor.new { puts "Hi, I am #{self.inspect}" }
|
|
366
|
-
# r.
|
|
322
|
+
# r.join
|
|
367
323
|
# # Prints "Hi, I am #<Ractor:#2 test.rb:1 running>"
|
|
368
324
|
#
|
|
369
325
|
# Any `args` passed are propagated to the block arguments by the same rules as
|
|
@@ -375,14 +331,14 @@ class Ractor
|
|
|
375
331
|
# r = Ractor.new(arg) {|received_arg|
|
|
376
332
|
# puts "Received: #{received_arg} (##{received_arg.object_id})"
|
|
377
333
|
# }
|
|
378
|
-
# r.
|
|
334
|
+
# r.join
|
|
379
335
|
# # Prints:
|
|
380
336
|
# # Passing: [1, 2, 3] (#280)
|
|
381
337
|
# # Received: [1, 2, 3] (#300)
|
|
382
338
|
#
|
|
383
339
|
# Ractor's `name` can be set for debugging purposes:
|
|
384
340
|
#
|
|
385
|
-
# r = Ractor.new(name: 'my ractor') {}; r.
|
|
341
|
+
# r = Ractor.new(name: 'my ractor') {}; r.join
|
|
386
342
|
# p r
|
|
387
343
|
# #=> #<Ractor:#3 my ractor test.rb:1 terminated>
|
|
388
344
|
#
|
|
@@ -390,128 +346,12 @@ class Ractor
|
|
|
390
346
|
|
|
391
347
|
# <!--
|
|
392
348
|
# rdoc-file=ractor.rb
|
|
393
|
-
# - Ractor.receive ->
|
|
349
|
+
# - Ractor.receive -> obj
|
|
394
350
|
# -->
|
|
395
|
-
#
|
|
396
|
-
# there by #send from another ractor).
|
|
397
|
-
#
|
|
398
|
-
# r = Ractor.new do
|
|
399
|
-
# v1 = Ractor.receive
|
|
400
|
-
# puts "Received: #{v1}"
|
|
401
|
-
# end
|
|
402
|
-
# r.send('message1')
|
|
403
|
-
# r.take
|
|
404
|
-
# # Here will be printed: "Received: message1"
|
|
405
|
-
#
|
|
406
|
-
# Alternatively, the private instance method `receive` may be used:
|
|
407
|
-
#
|
|
408
|
-
# r = Ractor.new do
|
|
409
|
-
# v1 = receive
|
|
410
|
-
# puts "Received: #{v1}"
|
|
411
|
-
# end
|
|
412
|
-
# r.send('message1')
|
|
413
|
-
# r.take
|
|
414
|
-
# # This prints: "Received: message1"
|
|
415
|
-
#
|
|
416
|
-
# The method blocks if the queue is empty.
|
|
417
|
-
#
|
|
418
|
-
# r = Ractor.new do
|
|
419
|
-
# puts "Before first receive"
|
|
420
|
-
# v1 = Ractor.receive
|
|
421
|
-
# puts "Received: #{v1}"
|
|
422
|
-
# v2 = Ractor.receive
|
|
423
|
-
# puts "Received: #{v2}"
|
|
424
|
-
# end
|
|
425
|
-
# wait
|
|
426
|
-
# puts "Still not received"
|
|
427
|
-
# r.send('message1')
|
|
428
|
-
# wait
|
|
429
|
-
# puts "Still received only one"
|
|
430
|
-
# r.send('message2')
|
|
431
|
-
# r.take
|
|
432
|
-
#
|
|
433
|
-
# Output:
|
|
434
|
-
#
|
|
435
|
-
# Before first receive
|
|
436
|
-
# Still not received
|
|
437
|
-
# Received: message1
|
|
438
|
-
# Still received only one
|
|
439
|
-
# Received: message2
|
|
440
|
-
#
|
|
441
|
-
# If close_incoming was called on the ractor, the method raises
|
|
442
|
-
# Ractor::ClosedError if there are no more messages in the incoming queue:
|
|
443
|
-
#
|
|
444
|
-
# Ractor.new do
|
|
445
|
-
# close_incoming
|
|
446
|
-
# receive
|
|
447
|
-
# end
|
|
448
|
-
# wait
|
|
449
|
-
# # in `receive': The incoming port is already closed => #<Ractor:#2 test.rb:1 running> (Ractor::ClosedError)
|
|
351
|
+
# Receives a message from the current ractor's default port.
|
|
450
352
|
#
|
|
451
353
|
def self.receive: () -> untyped
|
|
452
354
|
|
|
453
|
-
# <!--
|
|
454
|
-
# rdoc-file=ractor.rb
|
|
455
|
-
# - Ractor.receive_if {|msg| block } -> msg
|
|
456
|
-
# -->
|
|
457
|
-
# Receive only a specific message.
|
|
458
|
-
#
|
|
459
|
-
# Instead of Ractor.receive, Ractor.receive_if can be given a pattern (or any
|
|
460
|
-
# filter) in a block and you can choose the messages to accept that are
|
|
461
|
-
# available in your ractor's incoming queue.
|
|
462
|
-
#
|
|
463
|
-
# r = Ractor.new do
|
|
464
|
-
# p Ractor.receive_if{|msg| msg.match?(/foo/)} #=> "foo3"
|
|
465
|
-
# p Ractor.receive_if{|msg| msg.match?(/bar/)} #=> "bar1"
|
|
466
|
-
# p Ractor.receive_if{|msg| msg.match?(/baz/)} #=> "baz2"
|
|
467
|
-
# end
|
|
468
|
-
# r << "bar1"
|
|
469
|
-
# r << "baz2"
|
|
470
|
-
# r << "foo3"
|
|
471
|
-
# r.take
|
|
472
|
-
#
|
|
473
|
-
# This will output:
|
|
474
|
-
#
|
|
475
|
-
# foo3
|
|
476
|
-
# bar1
|
|
477
|
-
# baz2
|
|
478
|
-
#
|
|
479
|
-
# If the block returns a truthy value, the message is removed from the incoming
|
|
480
|
-
# queue and returned. Otherwise, the message remains in the incoming queue and
|
|
481
|
-
# the next messages are checked by the given block.
|
|
482
|
-
#
|
|
483
|
-
# If there are no messages left in the incoming queue, the method will block
|
|
484
|
-
# until new messages arrive.
|
|
485
|
-
#
|
|
486
|
-
# If the block is escaped by break/return/exception/throw, the message is
|
|
487
|
-
# removed from the incoming queue as if a truthy value had been returned.
|
|
488
|
-
#
|
|
489
|
-
# r = Ractor.new do
|
|
490
|
-
# val = Ractor.receive_if{|msg| msg.is_a?(Array)}
|
|
491
|
-
# puts "Received successfully: #{val}"
|
|
492
|
-
# end
|
|
493
|
-
#
|
|
494
|
-
# r.send(1)
|
|
495
|
-
# r.send('test')
|
|
496
|
-
# wait
|
|
497
|
-
# puts "2 non-matching sent, nothing received"
|
|
498
|
-
# r.send([1, 2, 3])
|
|
499
|
-
# wait
|
|
500
|
-
#
|
|
501
|
-
# Prints:
|
|
502
|
-
#
|
|
503
|
-
# 2 non-matching sent, nothing received
|
|
504
|
-
# Received successfully: [1, 2, 3]
|
|
505
|
-
#
|
|
506
|
-
# Note that you can not call receive/receive_if in the given block recursively.
|
|
507
|
-
# You should not do any tasks in the block other than message filtration.
|
|
508
|
-
#
|
|
509
|
-
# Ractor.current << true
|
|
510
|
-
# Ractor.receive_if{|msg| Ractor.receive}
|
|
511
|
-
# #=> `receive': can not call receive/receive_if recursively (Ractor::Error)
|
|
512
|
-
#
|
|
513
|
-
def self.receive_if: () { (untyped) -> boolish } -> untyped
|
|
514
|
-
|
|
515
355
|
# <!--
|
|
516
356
|
# rdoc-file=ractor.rb
|
|
517
357
|
# - recv()
|
|
@@ -521,57 +361,51 @@ class Ractor
|
|
|
521
361
|
|
|
522
362
|
# <!--
|
|
523
363
|
# rdoc-file=ractor.rb
|
|
524
|
-
# - Ractor.select(*
|
|
364
|
+
# - Ractor.select(*ractors_or_ports) -> [ractor or port, obj]
|
|
525
365
|
# -->
|
|
526
|
-
#
|
|
527
|
-
#
|
|
528
|
-
#
|
|
529
|
-
#
|
|
530
|
-
#
|
|
531
|
-
#
|
|
532
|
-
#
|
|
533
|
-
#
|
|
534
|
-
#
|
|
535
|
-
#
|
|
536
|
-
#
|
|
537
|
-
#
|
|
538
|
-
#
|
|
539
|
-
#
|
|
540
|
-
#
|
|
541
|
-
#
|
|
542
|
-
# main.send 'to main'
|
|
543
|
-
# Ractor.yield 'from 1'
|
|
544
|
-
# end
|
|
545
|
-
# r2 = Ractor.new do
|
|
546
|
-
# Ractor.yield 'from 2'
|
|
366
|
+
# Blocks the current Thread until one of the given ports has received a message.
|
|
367
|
+
# Returns an array of two elements where the first element is the Port and the
|
|
368
|
+
# second is the received object. This method can also accept Ractor objects
|
|
369
|
+
# themselves, and in that case will wait until one has terminated and return a
|
|
370
|
+
# two-element array where the first element is the ractor and the second is its
|
|
371
|
+
# termination value.
|
|
372
|
+
#
|
|
373
|
+
# p1, p2 = Ractor::Port.new, Ractor::Port.new
|
|
374
|
+
# ps = [p1, p2]
|
|
375
|
+
# rs = 2.times.map do |i|
|
|
376
|
+
# Ractor.new(ps.shift, i) do |p, i|
|
|
377
|
+
# sleep rand(0.99)
|
|
378
|
+
# p.send("r#{i}")
|
|
379
|
+
# sleep rand(0.99)
|
|
380
|
+
# "r#{i} done"
|
|
381
|
+
# end
|
|
547
382
|
# end
|
|
548
383
|
#
|
|
549
|
-
#
|
|
550
|
-
#
|
|
551
|
-
#
|
|
552
|
-
#
|
|
553
|
-
#
|
|
554
|
-
# calling #take. In this case, the pair `[:yield, nil]` is returned:
|
|
555
|
-
#
|
|
556
|
-
# r1 = Ractor.new(Ractor.current) do |main|
|
|
557
|
-
# puts "Received from main: #{main.take}"
|
|
384
|
+
# waiting_on = [p1, p2, *rs]
|
|
385
|
+
# until waiting_on.empty?
|
|
386
|
+
# received_on, obj = Ractor.select(*waiting_on)
|
|
387
|
+
# waiting_on.delete(received_on)
|
|
388
|
+
# puts obj
|
|
558
389
|
# end
|
|
559
390
|
#
|
|
560
|
-
#
|
|
561
|
-
#
|
|
562
|
-
#
|
|
563
|
-
#
|
|
564
|
-
#
|
|
565
|
-
#
|
|
566
|
-
#
|
|
567
|
-
#
|
|
568
|
-
#
|
|
569
|
-
#
|
|
570
|
-
#
|
|
571
|
-
#
|
|
572
|
-
#
|
|
391
|
+
# # r0
|
|
392
|
+
# # r1
|
|
393
|
+
# # r1 done
|
|
394
|
+
# # r0 done
|
|
395
|
+
#
|
|
396
|
+
# The following example is almost equivalent to
|
|
397
|
+
# <code>ractors.map(&:value)</code> except the thread is unblocked when any of
|
|
398
|
+
# the ractors has terminated as opposed to waiting for their termination in the
|
|
399
|
+
# array element order.
|
|
400
|
+
#
|
|
401
|
+
# values = []
|
|
402
|
+
# until ractors.empty?
|
|
403
|
+
# r, val = Ractor.select(*ractors)
|
|
404
|
+
# ractors.delete(r)
|
|
405
|
+
# values << val
|
|
406
|
+
# end
|
|
573
407
|
#
|
|
574
|
-
def self.select: (
|
|
408
|
+
def self.select: (?) -> Array[untyped]
|
|
575
409
|
|
|
576
410
|
# <!--
|
|
577
411
|
# rdoc-file=ractor.rb
|
|
@@ -579,7 +413,7 @@ class Ractor
|
|
|
579
413
|
# -->
|
|
580
414
|
# Checks if the object is shareable by ractors.
|
|
581
415
|
#
|
|
582
|
-
# Ractor.shareable?(1) #=> true -- numbers
|
|
416
|
+
# Ractor.shareable?(1) #=> true -- numbers are shareable
|
|
583
417
|
# Ractor.shareable?('foo') #=> false, unless the string is frozen due to # frozen_string_literal: true
|
|
584
418
|
# Ractor.shareable?('foo'.freeze) #=> true
|
|
585
419
|
#
|
|
@@ -590,291 +424,171 @@ class Ractor
|
|
|
590
424
|
|
|
591
425
|
# <!--
|
|
592
426
|
# rdoc-file=ractor.rb
|
|
593
|
-
# - Ractor.
|
|
427
|
+
# - Ractor.shareable_proc(self: nil){} -> shareable proc
|
|
594
428
|
# -->
|
|
595
|
-
#
|
|
596
|
-
#
|
|
597
|
-
#
|
|
429
|
+
# Returns a shareable copy of the given block's Proc. The value of `self` in the
|
|
430
|
+
# Proc will be replaced with the value passed via the <code>self:</code>
|
|
431
|
+
# keyword, or `nil` if not given.
|
|
598
432
|
#
|
|
599
|
-
#
|
|
600
|
-
# Thread.new(it){|i|
|
|
601
|
-
# Ractor.store_if_absent(:s){ f(); i }
|
|
602
|
-
# #=> return stored value of key :s
|
|
603
|
-
# }
|
|
604
|
-
# }.map(&:value).uniq.size #=> 1 and f() is called only once
|
|
433
|
+
# In a shareable Proc, access to any outer variables if prohibited.
|
|
605
434
|
#
|
|
606
|
-
|
|
435
|
+
# a = 42
|
|
436
|
+
# Ractor.shareable_proc{ p a }
|
|
437
|
+
# #=> can not isolate a Proc because it accesses outer variables (a). (ArgumentError)
|
|
438
|
+
#
|
|
439
|
+
# The value of `self` in the Proc must be a shareable object.
|
|
440
|
+
#
|
|
441
|
+
# Ractor.shareable_proc(self: self){}
|
|
442
|
+
# #=> self should be shareable: main (Ractor::IsolationError)
|
|
443
|
+
#
|
|
444
|
+
def self.shareable_proc: [T] () { (?) [self: nil] -> T } -> ^(?) [self: nil] -> T
|
|
445
|
+
| [T, S] (self: S) { (?) [self: S] -> T } -> ^(?) [self: S] -> T
|
|
607
446
|
|
|
608
447
|
# <!--
|
|
609
448
|
# rdoc-file=ractor.rb
|
|
610
|
-
# - Ractor.
|
|
449
|
+
# - Ractor.shareable_lambda(self: nil){} -> shareable lambda
|
|
611
450
|
# -->
|
|
612
|
-
#
|
|
451
|
+
# Same as Ractor.shareable_proc, but returns a lambda Proc.
|
|
613
452
|
#
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
# # Prints: "Hello from ractor"
|
|
617
|
-
#
|
|
618
|
-
# This method is blocking, and will return only when somebody consumes the sent
|
|
619
|
-
# message.
|
|
620
|
-
#
|
|
621
|
-
# r = Ractor.new do
|
|
622
|
-
# Ractor.yield 'Hello from ractor'
|
|
623
|
-
# puts "Ractor: after yield"
|
|
624
|
-
# end
|
|
625
|
-
# wait
|
|
626
|
-
# puts "Still not taken"
|
|
627
|
-
# puts r.take
|
|
628
|
-
#
|
|
629
|
-
# This will print:
|
|
630
|
-
#
|
|
631
|
-
# Still not taken
|
|
632
|
-
# Hello from ractor
|
|
633
|
-
# Ractor: after yield
|
|
634
|
-
#
|
|
635
|
-
# If the outgoing port was closed with #close_outgoing, the method will raise:
|
|
636
|
-
#
|
|
637
|
-
# r = Ractor.new do
|
|
638
|
-
# close_outgoing
|
|
639
|
-
# Ractor.yield 'Hello from ractor'
|
|
640
|
-
# end
|
|
641
|
-
# wait
|
|
642
|
-
# # `yield': The outgoing-port is already closed (Ractor::ClosedError)
|
|
643
|
-
#
|
|
644
|
-
# The meaning of the `move` argument is the same as for #send.
|
|
645
|
-
#
|
|
646
|
-
def self.yield: (untyped obj, ?move: boolish) -> untyped
|
|
453
|
+
def self.shareable_lambda: [T] () { (?) [self: nil] -> T } -> ^(?) [self: nil] -> T
|
|
454
|
+
| [T, S] (self: S) { (?) [self: S] -> T } -> ^(?) [self: S] -> T
|
|
647
455
|
|
|
648
456
|
# <!--
|
|
649
457
|
# rdoc-file=ractor.rb
|
|
650
|
-
# -
|
|
458
|
+
# - Ractor.store_if_absent(key){ init_block }
|
|
651
459
|
# -->
|
|
460
|
+
# If the corresponding ractor-local value is not set, yields a value with
|
|
461
|
+
# init_block and stores the value in a thread-safe manner. This method returns
|
|
462
|
+
# the stored value.
|
|
463
|
+
#
|
|
464
|
+
# (1..10).map{
|
|
465
|
+
# Thread.new(it){|i|
|
|
466
|
+
# Ractor.store_if_absent(:s){ f(); i }
|
|
467
|
+
# #=> return stored value of key :s
|
|
468
|
+
# }
|
|
469
|
+
# }.map(&:value).uniq.size #=> 1 and f() is called only once
|
|
652
470
|
#
|
|
471
|
+
def self.store_if_absent: [A] (Symbol) { (nil) -> A } -> A
|
|
472
|
+
|
|
653
473
|
alias << send
|
|
654
474
|
|
|
655
475
|
# <!--
|
|
656
476
|
# rdoc-file=ractor.rb
|
|
657
477
|
# - [](sym)
|
|
658
478
|
# -->
|
|
659
|
-
#
|
|
479
|
+
# Gets a value from ractor-local storage for the current Ractor. Obsolete, use
|
|
660
480
|
# Ractor.[] instead.
|
|
661
481
|
#
|
|
482
|
+
%a{deprecated: Use Ractor.[] instead}
|
|
662
483
|
def []: (interned sym) -> untyped
|
|
663
484
|
|
|
664
485
|
# <!--
|
|
665
486
|
# rdoc-file=ractor.rb
|
|
666
487
|
# - []=(sym, val)
|
|
667
488
|
# -->
|
|
668
|
-
#
|
|
489
|
+
# Sets a value in ractor-local storage for the current Ractor. Obsolete, use
|
|
669
490
|
# Ractor.[]= instead.
|
|
670
491
|
#
|
|
492
|
+
%a{deprecated: Use Ractor.[]= instead}
|
|
671
493
|
def []=: [T] (interned sym, T val) -> T
|
|
672
494
|
|
|
673
495
|
# <!--
|
|
674
496
|
# rdoc-file=ractor.rb
|
|
675
|
-
# - ractor.
|
|
497
|
+
# - ractor.default_port -> port object
|
|
676
498
|
# -->
|
|
677
|
-
#
|
|
678
|
-
# further attempts to Ractor.receive in the ractor, and #send to the ractor will
|
|
679
|
-
# fail with Ractor::ClosedError.
|
|
680
|
-
#
|
|
681
|
-
# r = Ractor.new {sleep(500)}
|
|
682
|
-
# r.close_incoming #=> false
|
|
683
|
-
# r.close_incoming #=> true
|
|
684
|
-
# r.send('test')
|
|
685
|
-
# # Ractor::ClosedError (The incoming-port is already closed)
|
|
499
|
+
# Returns the default port of the Ractor.
|
|
686
500
|
#
|
|
687
|
-
def
|
|
501
|
+
def default_port: () -> Port[untyped]
|
|
688
502
|
|
|
689
503
|
# <!--
|
|
690
504
|
# rdoc-file=ractor.rb
|
|
691
|
-
# -
|
|
505
|
+
# - inspect()
|
|
692
506
|
# -->
|
|
693
|
-
# Closes the outgoing port and returns whether it was already closed. All
|
|
694
|
-
# further attempts to Ractor.yield in the ractor, and #take from the ractor will
|
|
695
|
-
# fail with Ractor::ClosedError.
|
|
696
507
|
#
|
|
697
|
-
|
|
698
|
-
# r.close_outgoing #=> false
|
|
699
|
-
# r.close_outgoing #=> true
|
|
700
|
-
# r.take
|
|
701
|
-
# # Ractor::ClosedError (The outgoing-port is already closed)
|
|
702
|
-
#
|
|
703
|
-
def close_outgoing: () -> bool
|
|
508
|
+
def inspect: () -> String
|
|
704
509
|
|
|
705
510
|
# <!--
|
|
706
511
|
# rdoc-file=ractor.rb
|
|
707
|
-
# -
|
|
512
|
+
# - ractor.join -> self
|
|
708
513
|
# -->
|
|
514
|
+
# Waits for the termination of the Ractor. If the Ractor was aborted (terminated
|
|
515
|
+
# by an unhandled exception), the exception is raised in the current ractor.
|
|
709
516
|
#
|
|
710
|
-
|
|
517
|
+
# Ractor.new{}.join #=> ractor
|
|
518
|
+
#
|
|
519
|
+
# Ractor.new{ raise "foo" }.join
|
|
520
|
+
# #=> raises the exception "foo (RuntimeError)"
|
|
521
|
+
#
|
|
522
|
+
def join: () -> self
|
|
711
523
|
|
|
712
524
|
# <!--
|
|
713
525
|
# rdoc-file=ractor.rb
|
|
714
526
|
# - name()
|
|
715
527
|
# -->
|
|
716
|
-
#
|
|
528
|
+
# Returns the name set in Ractor.new, or `nil`.
|
|
717
529
|
#
|
|
718
530
|
def name: () -> String?
|
|
719
531
|
|
|
720
532
|
# <!--
|
|
721
533
|
# rdoc-file=ractor.rb
|
|
722
|
-
# - ractor.
|
|
534
|
+
# - ractor.monitor(port) -> self
|
|
723
535
|
# -->
|
|
724
|
-
#
|
|
725
|
-
#
|
|
726
|
-
# r = Ractor.new do
|
|
727
|
-
# value = Ractor.receive
|
|
728
|
-
# puts "Received #{value}"
|
|
729
|
-
# end
|
|
730
|
-
# r.send 'message'
|
|
731
|
-
# # Prints: "Received: message"
|
|
732
|
-
#
|
|
733
|
-
# The method is non-blocking (will return immediately even if the ractor is not
|
|
734
|
-
# ready to receive anything):
|
|
735
|
-
#
|
|
736
|
-
# r = Ractor.new {sleep(5)}
|
|
737
|
-
# r.send('test')
|
|
738
|
-
# puts "Sent successfully"
|
|
739
|
-
# # Prints: "Sent successfully" immediately
|
|
740
|
-
#
|
|
741
|
-
# An attempt to send to a ractor which already finished its execution will raise
|
|
742
|
-
# Ractor::ClosedError.
|
|
743
|
-
#
|
|
744
|
-
# r = Ractor.new {}
|
|
745
|
-
# r.take
|
|
746
|
-
# p r
|
|
747
|
-
# # "#<Ractor:#6 (irb):23 terminated>"
|
|
748
|
-
# r.send('test')
|
|
749
|
-
# # Ractor::ClosedError (The incoming-port is already closed)
|
|
750
|
-
#
|
|
751
|
-
# If close_incoming was called on the ractor, the method also raises
|
|
752
|
-
# Ractor::ClosedError.
|
|
536
|
+
# Registers the port as a monitoring port for this ractor. When the ractor
|
|
537
|
+
# terminates, the port receives a Symbol object.
|
|
753
538
|
#
|
|
754
|
-
#
|
|
755
|
-
#
|
|
756
|
-
#
|
|
757
|
-
#
|
|
758
|
-
# r.close_incoming
|
|
759
|
-
# r.send('test')
|
|
760
|
-
# # Ractor::ClosedError (The incoming-port is already closed)
|
|
761
|
-
# # The error is raised immediately, not when the ractor tries to receive
|
|
762
|
-
#
|
|
763
|
-
# If the `obj` is unshareable, by default it will be copied into the receiving
|
|
764
|
-
# ractor by deep cloning. If `move: true` is passed, the object is *moved* into
|
|
765
|
-
# the receiving ractor and becomes inaccessible to the sender.
|
|
766
|
-
#
|
|
767
|
-
# r = Ractor.new {puts "Received: #{receive}"}
|
|
768
|
-
# msg = 'message'
|
|
769
|
-
# r.send(msg, move: true)
|
|
770
|
-
# r.take
|
|
771
|
-
# p msg
|
|
772
|
-
#
|
|
773
|
-
# This prints:
|
|
539
|
+
# * <code>:exited</code> is sent if the ractor terminates without an unhandled
|
|
540
|
+
# exception.
|
|
541
|
+
# * <code>:aborted</code> is sent if the ractor terminates by an unhandled
|
|
542
|
+
# exception.
|
|
774
543
|
#
|
|
775
|
-
#
|
|
776
|
-
#
|
|
544
|
+
# r = Ractor.new{ some_task() }
|
|
545
|
+
# r.monitor(port = Ractor::Port.new)
|
|
546
|
+
# port.receive #=> :exited and r is terminated
|
|
777
547
|
#
|
|
778
|
-
#
|
|
548
|
+
# r = Ractor.new{ raise "foo" }
|
|
549
|
+
# r.monitor(port = Ractor::Port.new)
|
|
550
|
+
# port.receive #=> :aborted and r is terminated by the RuntimeError "foo"
|
|
779
551
|
#
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
#
|
|
783
|
-
#
|
|
784
|
-
#
|
|
785
|
-
#
|
|
786
|
-
#
|
|
787
|
-
# # Ractor::MovedError (can not send any methods to a moved object)
|
|
788
|
-
# ary.class
|
|
789
|
-
# # Ractor::MovedError (can not send any methods to a moved object)
|
|
790
|
-
# copy.class
|
|
791
|
-
# # => Array, it is different object
|
|
792
|
-
# copy[0].inspect
|
|
793
|
-
# # Ractor::MovedError (can not send any methods to a moved object)
|
|
794
|
-
# # ...but its item was still a reference to `s`, which was moved
|
|
795
|
-
#
|
|
796
|
-
# If the object is shareable, `move: true` has no effect on it:
|
|
797
|
-
#
|
|
798
|
-
# r = Ractor.new {puts "Received: #{receive}"}
|
|
799
|
-
# s = 'message'.freeze
|
|
800
|
-
# r.send(s, move: true)
|
|
801
|
-
# s.inspect #=> "message", still available
|
|
552
|
+
def monitor: [T < Symbol] (Port[T]) -> untyped
|
|
553
|
+
|
|
554
|
+
# <!--
|
|
555
|
+
# rdoc-file=ractor.rb
|
|
556
|
+
# - ractor.send(msg, move: false) -> self
|
|
557
|
+
# -->
|
|
558
|
+
# This is equivalent to Port#send to the ractor's #default_port.
|
|
802
559
|
#
|
|
803
560
|
def send: (untyped obj, ?move: boolish) -> Ractor
|
|
804
561
|
|
|
805
562
|
# <!--
|
|
806
563
|
# rdoc-file=ractor.rb
|
|
807
|
-
# -
|
|
564
|
+
# - to_s()
|
|
808
565
|
# -->
|
|
809
|
-
# Get a message from the ractor's outgoing port, which was put there by
|
|
810
|
-
# Ractor.yield or at ractor's termination.
|
|
811
|
-
#
|
|
812
|
-
# r = Ractor.new do
|
|
813
|
-
# Ractor.yield 'explicit yield'
|
|
814
|
-
# 'last value'
|
|
815
|
-
# end
|
|
816
|
-
# puts r.take #=> 'explicit yield'
|
|
817
|
-
# puts r.take #=> 'last value'
|
|
818
|
-
# puts r.take # Ractor::ClosedError (The outgoing-port is already closed)
|
|
819
|
-
#
|
|
820
|
-
# The fact that the last value is also sent to the outgoing port means that
|
|
821
|
-
# `take` can be used as an analog of Thread#join ("just wait until ractor
|
|
822
|
-
# finishes"). However, it will raise if somebody has already consumed that
|
|
823
|
-
# message.
|
|
824
566
|
#
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
#
|
|
828
|
-
#
|
|
829
|
-
#
|
|
830
|
-
#
|
|
831
|
-
#
|
|
832
|
-
# r.close_outgoing
|
|
833
|
-
# r.take
|
|
834
|
-
# # Ractor::ClosedError (The outgoing-port is already closed)
|
|
835
|
-
# # The error would be raised immediately, not when ractor will try to receive
|
|
836
|
-
#
|
|
837
|
-
# If an uncaught exception is raised in the Ractor, it is propagated by take as
|
|
838
|
-
# a Ractor::RemoteError.
|
|
839
|
-
#
|
|
840
|
-
# r = Ractor.new {raise "Something weird happened"}
|
|
841
|
-
#
|
|
842
|
-
# begin
|
|
843
|
-
# r.take
|
|
844
|
-
# rescue => e
|
|
845
|
-
# p e # => #<Ractor::RemoteError: thrown by remote Ractor.>
|
|
846
|
-
# p e.ractor == r # => true
|
|
847
|
-
# p e.cause # => #<RuntimeError: Something weird happened>
|
|
848
|
-
# end
|
|
849
|
-
#
|
|
850
|
-
# Ractor::ClosedError is a descendant of StopIteration, so the termination of
|
|
851
|
-
# the ractor will break out of any loops that receive this message without
|
|
852
|
-
# propagating the error:
|
|
853
|
-
#
|
|
854
|
-
# r = Ractor.new do
|
|
855
|
-
# 3.times {|i| Ractor.yield "message #{i}"}
|
|
856
|
-
# "finishing"
|
|
857
|
-
# end
|
|
858
|
-
#
|
|
859
|
-
# loop {puts "Received: " + r.take}
|
|
860
|
-
# puts "Continue successfully"
|
|
861
|
-
#
|
|
862
|
-
# This will print:
|
|
863
|
-
#
|
|
864
|
-
# Received: message 0
|
|
865
|
-
# Received: message 1
|
|
866
|
-
# Received: message 2
|
|
867
|
-
# Received: finishing
|
|
868
|
-
# Continue successfully
|
|
567
|
+
alias to_s inspect
|
|
568
|
+
|
|
569
|
+
# <!--
|
|
570
|
+
# rdoc-file=ractor.rb
|
|
571
|
+
# - ractor.unmonitor(port) -> self
|
|
572
|
+
# -->
|
|
573
|
+
# Unregisters the port from the monitoring ports for this ractor.
|
|
869
574
|
#
|
|
870
|
-
def
|
|
575
|
+
def unmonitor: (Port[untyped]) -> self
|
|
871
576
|
|
|
872
577
|
# <!--
|
|
873
578
|
# rdoc-file=ractor.rb
|
|
874
|
-
# -
|
|
579
|
+
# - ractor.value -> obj
|
|
875
580
|
# -->
|
|
581
|
+
# Waits for `ractor` to complete and returns its value or raises the exception
|
|
582
|
+
# which terminated the Ractor. The termination value will be moved to the
|
|
583
|
+
# calling Ractor. Therefore, at most 1 Ractor can receive another ractor's
|
|
584
|
+
# termination value.
|
|
876
585
|
#
|
|
877
|
-
|
|
586
|
+
# r = Ractor.new{ [1, 2] }
|
|
587
|
+
# r.value #=> [1, 2] (unshareable object)
|
|
588
|
+
#
|
|
589
|
+
# Ractor.new(r){|r| r.value} #=> Ractor::Error
|
|
590
|
+
#
|
|
591
|
+
def value: () -> untyped
|
|
878
592
|
|
|
879
593
|
private
|
|
880
594
|
|
|
@@ -904,49 +618,35 @@ class Ractor
|
|
|
904
618
|
# <!-- rdoc-file=ractor.c -->
|
|
905
619
|
# Raised when an attempt is made to send a message to a closed port, or to
|
|
906
620
|
# retrieve a message from a closed and empty port. Ports may be closed
|
|
907
|
-
# explicitly with Ractor#
|
|
908
|
-
#
|
|
909
|
-
#
|
|
910
|
-
# r = Ractor.new { sleep(500) }
|
|
911
|
-
# r.close_outgoing
|
|
912
|
-
# r.take # Ractor::ClosedError
|
|
913
|
-
#
|
|
914
|
-
# ClosedError is a descendant of StopIteration, so the closing of the ractor
|
|
915
|
-
# will break the loops without propagating the error:
|
|
621
|
+
# explicitly with Ractor::Port#close and are closed implicitly when a Ractor
|
|
622
|
+
# terminates.
|
|
916
623
|
#
|
|
917
|
-
#
|
|
918
|
-
#
|
|
919
|
-
#
|
|
920
|
-
#
|
|
921
|
-
# end
|
|
922
|
-
# puts "loop exited"
|
|
923
|
-
# end
|
|
924
|
-
#
|
|
925
|
-
# 3.times{|i| r << i}
|
|
926
|
-
# r.close_incoming
|
|
927
|
-
# r.take
|
|
928
|
-
# puts "Continue successfully"
|
|
624
|
+
# port = Ractor::Port.new
|
|
625
|
+
# port.close
|
|
626
|
+
# port << "test" # Ractor::ClosedError
|
|
627
|
+
# port.receive # Ractor::ClosedError
|
|
929
628
|
#
|
|
930
|
-
#
|
|
931
|
-
#
|
|
932
|
-
# Received: 0
|
|
933
|
-
# Received: 1
|
|
934
|
-
# Received: 2
|
|
935
|
-
# loop exited
|
|
936
|
-
# Continue successfully
|
|
629
|
+
# ClosedError is a descendant of StopIteration, so the closing of a port will
|
|
630
|
+
# break out of loops without propagating the error.
|
|
937
631
|
#
|
|
938
632
|
class ClosedError < StopIteration
|
|
939
633
|
end
|
|
940
634
|
|
|
635
|
+
# <!-- rdoc-file=ractor.c -->
|
|
636
|
+
# The parent class of Ractor-related error classes.
|
|
637
|
+
#
|
|
941
638
|
class Error < RuntimeError
|
|
942
639
|
end
|
|
943
640
|
|
|
641
|
+
# <!-- rdoc-file=ractor.c -->
|
|
642
|
+
# Raised on attempt to make a Ractor-unshareable object Ractor-shareable.
|
|
643
|
+
#
|
|
944
644
|
class IsolationError < Ractor::Error
|
|
945
645
|
end
|
|
946
646
|
|
|
947
647
|
# <!-- rdoc-file=ractor.c -->
|
|
948
648
|
# Raised on an attempt to access an object which was moved in Ractor#send or
|
|
949
|
-
# Ractor.
|
|
649
|
+
# Ractor::Port#send.
|
|
950
650
|
#
|
|
951
651
|
# r = Ractor.new { sleep }
|
|
952
652
|
#
|
|
@@ -960,7 +660,7 @@ class Ractor
|
|
|
960
660
|
|
|
961
661
|
# <!-- rdoc-file=ractor.c -->
|
|
962
662
|
# A special object which replaces any value that was moved to another ractor in
|
|
963
|
-
# Ractor#send or Ractor.
|
|
663
|
+
# Ractor#send or Ractor::Port#send. Any attempt to access the object results in
|
|
964
664
|
# Ractor::MovedError.
|
|
965
665
|
#
|
|
966
666
|
# r = Ractor.new { receive }
|
|
@@ -1037,15 +737,158 @@ class Ractor
|
|
|
1037
737
|
def method_missing: (*untyped) -> untyped
|
|
1038
738
|
end
|
|
1039
739
|
|
|
740
|
+
# <!-- rdoc-file=ractor.rb -->
|
|
741
|
+
# Port objects transmit messages between Ractors.
|
|
742
|
+
#
|
|
743
|
+
class Port[T = untyped]
|
|
744
|
+
alias << send
|
|
745
|
+
|
|
746
|
+
# <!--
|
|
747
|
+
# rdoc-file=ractor.rb
|
|
748
|
+
# - port.close
|
|
749
|
+
# -->
|
|
750
|
+
# Closes the port. Sending to a closed port is prohibited. Receiving is also
|
|
751
|
+
# prohibited if there are no messages in its message queue.
|
|
752
|
+
#
|
|
753
|
+
# Only the Ractor which created the port is allowed to close it.
|
|
754
|
+
#
|
|
755
|
+
# port = Ractor::Port.new
|
|
756
|
+
# Ractor.new port do |port|
|
|
757
|
+
# port.close #=> closing port by other ractors is not allowed (Ractor::Error)
|
|
758
|
+
# end.join
|
|
759
|
+
#
|
|
760
|
+
def close: () -> void
|
|
761
|
+
|
|
762
|
+
# <!--
|
|
763
|
+
# rdoc-file=ractor.rb
|
|
764
|
+
# - port.closed? -> true/false
|
|
765
|
+
# -->
|
|
766
|
+
# Returns whether or not the port is closed.
|
|
767
|
+
#
|
|
768
|
+
def closed?: () -> bool
|
|
769
|
+
|
|
770
|
+
# <!--
|
|
771
|
+
# rdoc-file=ractor.rb
|
|
772
|
+
# - port.inspect -> string
|
|
773
|
+
# -->
|
|
774
|
+
#
|
|
775
|
+
def inspect: () -> String
|
|
776
|
+
|
|
777
|
+
# <!--
|
|
778
|
+
# rdoc-file=ractor.rb
|
|
779
|
+
# - port.receive -> msg
|
|
780
|
+
# -->
|
|
781
|
+
# Receives a message from the port (which was sent there by Port#send). Only the
|
|
782
|
+
# ractor that created the port can receive messages this way.
|
|
783
|
+
#
|
|
784
|
+
# port = Ractor::Port.new
|
|
785
|
+
# r = Ractor.new port do |port|
|
|
786
|
+
# port.send('message1')
|
|
787
|
+
# end
|
|
788
|
+
#
|
|
789
|
+
# v1 = port.receive
|
|
790
|
+
# puts "Received: #{v1}"
|
|
791
|
+
# r.join
|
|
792
|
+
# # This will print: "Received: message1"
|
|
793
|
+
#
|
|
794
|
+
# The method blocks the current Thread if the message queue is empty.
|
|
795
|
+
#
|
|
796
|
+
# port = Ractor::Port.new
|
|
797
|
+
# r = Ractor.new port do |port|
|
|
798
|
+
# wait
|
|
799
|
+
# puts "Still not received"
|
|
800
|
+
# port.send('message1')
|
|
801
|
+
# wait
|
|
802
|
+
# puts "Still received only one"
|
|
803
|
+
# port.send('message2')
|
|
804
|
+
# end
|
|
805
|
+
# puts "Before first receive"
|
|
806
|
+
# v1 = port.receive
|
|
807
|
+
# puts "Received: #{v1}"
|
|
808
|
+
# v2 = port.receive
|
|
809
|
+
# puts "Received: #{v2}"
|
|
810
|
+
# r.join
|
|
811
|
+
#
|
|
812
|
+
# Output:
|
|
813
|
+
#
|
|
814
|
+
# Before first receive
|
|
815
|
+
# Still not received
|
|
816
|
+
# Received: message1
|
|
817
|
+
# Still received only one
|
|
818
|
+
# Received: message2
|
|
819
|
+
#
|
|
820
|
+
# If the port is closed and there are no more messages in the message queue, the
|
|
821
|
+
# method raises Ractor::ClosedError.
|
|
822
|
+
#
|
|
823
|
+
# port = Ractor::Port.new
|
|
824
|
+
# port.close
|
|
825
|
+
# port.receive #=> raise Ractor::ClosedError
|
|
826
|
+
#
|
|
827
|
+
def receive: () -> T
|
|
828
|
+
|
|
829
|
+
# <!--
|
|
830
|
+
# rdoc-file=ractor.rb
|
|
831
|
+
# - port.send(msg, move: false) -> self
|
|
832
|
+
# -->
|
|
833
|
+
# Sends a message to the port to be accepted by port.receive.
|
|
834
|
+
#
|
|
835
|
+
# port = Ractor::Port.new
|
|
836
|
+
# r = Ractor.new(port) do |port|
|
|
837
|
+
# port.send 'message'
|
|
838
|
+
# end
|
|
839
|
+
# value = port.receive
|
|
840
|
+
# puts "Received #{value}"
|
|
841
|
+
# # Prints: "Received: message"
|
|
842
|
+
#
|
|
843
|
+
# The method is non-blocking (it will return immediately even if the ractor that
|
|
844
|
+
# created the port is not ready to receive anything):
|
|
845
|
+
#
|
|
846
|
+
# port = Ractor::Port.new
|
|
847
|
+
# r = Ractor.new(port) do |port|
|
|
848
|
+
# port.send 'test'
|
|
849
|
+
# puts "Sent successfully"
|
|
850
|
+
# # Prints: "Sent successfully" immediately
|
|
851
|
+
# end
|
|
852
|
+
#
|
|
853
|
+
# An attempt to send to a closed port will raise Ractor::ClosedError.
|
|
854
|
+
#
|
|
855
|
+
# r = Ractor.new {Ractor::Port.new}
|
|
856
|
+
# r.join
|
|
857
|
+
# p r
|
|
858
|
+
# # "#<Ractor:#6 (irb):23 terminated>"
|
|
859
|
+
# port = r.value
|
|
860
|
+
# port.send('test') # raise Ractor::ClosedError
|
|
861
|
+
#
|
|
862
|
+
# If the `obj` is unshareable, by default it will be copied into the receiving
|
|
863
|
+
# ractor by deep cloning.
|
|
864
|
+
#
|
|
865
|
+
# If the object is shareable, a reference to the object will be sent to the
|
|
866
|
+
# receiving ractor.
|
|
867
|
+
#
|
|
868
|
+
def send: (T obj, ?move: boolish) -> self
|
|
869
|
+
|
|
870
|
+
private
|
|
871
|
+
|
|
872
|
+
# <!--
|
|
873
|
+
# rdoc-file=ractor_sync.c
|
|
874
|
+
# - Ractor::Port.new -> new_port
|
|
875
|
+
# -->
|
|
876
|
+
# Returns a new Ractor::Port object.
|
|
877
|
+
#
|
|
878
|
+
def initialize: () -> void
|
|
879
|
+
|
|
880
|
+
def initialize_copy: (untyped) -> untyped
|
|
881
|
+
end
|
|
882
|
+
|
|
1040
883
|
# <!-- rdoc-file=ractor.c -->
|
|
1041
|
-
# Raised on
|
|
1042
|
-
# Ractor. Its `cause` will contain the original exception, and `ractor` is
|
|
1043
|
-
# original ractor it was raised in.
|
|
884
|
+
# Raised on Ractor#join or Ractor#value if there was an uncaught exception in
|
|
885
|
+
# the Ractor. Its `cause` will contain the original exception, and `ractor` is
|
|
886
|
+
# the original ractor it was raised in.
|
|
1044
887
|
#
|
|
1045
888
|
# r = Ractor.new { raise "Something weird happened" }
|
|
1046
889
|
#
|
|
1047
890
|
# begin
|
|
1048
|
-
# r.
|
|
891
|
+
# r.value
|
|
1049
892
|
# rescue => e
|
|
1050
893
|
# p e # => #<Ractor::RemoteError: thrown by remote Ractor.>
|
|
1051
894
|
# p e.ractor == r # => true
|
|
@@ -1054,11 +897,14 @@ class Ractor
|
|
|
1054
897
|
#
|
|
1055
898
|
class RemoteError < Ractor::Error
|
|
1056
899
|
# <!-- rdoc-file=ractor.rb -->
|
|
1057
|
-
# The Ractor
|
|
900
|
+
# The Ractor in which the uncaught exception was raised.
|
|
1058
901
|
#
|
|
1059
902
|
def ractor: () -> Ractor
|
|
1060
903
|
end
|
|
1061
904
|
|
|
905
|
+
# <!-- rdoc-file=ractor.c -->
|
|
906
|
+
# Raised when Ractor-unsafe C-methods is invoked by a non-main Ractor.
|
|
907
|
+
#
|
|
1062
908
|
class UnsafeError < Ractor::Error
|
|
1063
909
|
end
|
|
1064
910
|
|