⚝
One Hat Cyber Team
⚝
Your IP:
216.73.216.189
Server IP:
109.199.105.153
Server:
Linux connect.inboxifs.com 5.15.0-152-generic #162-Ubuntu SMP Wed Jul 23 09:48:42 UTC 2025 x86_64
Server Software:
Apache
PHP Version:
8.2.29
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
share
/
ri
/
3.0.0
/
system
/
Ractor
/
View File Name :
cdesc-Ractor.ri
U:RDoc::NormalClass[iI"Ractor:ET@I"Object;To:RDoc::Markup::Document:@parts[o;;[ : @fileI" ractor.c;T:0@omit_headings_from_table_of_contents_below0o;;[Qo:RDoc::Markup::Paragraph;[I"_Ractor is a Actor-model abstraction for Ruby that provides thread-safe parallel execution.;To:RDoc::Markup::BlankLine o;;[I"@Ractor.new can make new Ractor and it will run in parallel.;T@o:RDoc::Markup::Verbatim;[ I"# The simplest ractor ;TI"-r = Ractor.new {puts "I am in Ractor!"} ;TI" r.take # wait it to finish ;TI"/# here "I am in Ractor!" would be printed ;T:@format0o;;[I"gRactors do not share usual objects, so the some kind of thread-safety concerns such as data-race, ;TI"Crace-conditions are not available on multi-ractor programming.;T@o;;[I"WTo achieve this, ractors severely limit object sharing between different ractors. ;TI"eFor example, unlike threads, ractors can't access each other's objects, nor any objects through ;TI""variables of the outer scope.;T@o; ;[ I"a = 1 ;TI"4r = Ractor.new {puts "I am in Ractor! a=#{a}"} ;TI"# fails immediately with ;TI"W# ArgumentError (can not isolate a Proc because it accesses outer variables (a).) ;T;0o;;[I"eOn CRuby (the default implementation), Global Virtual Machine Lock (GVL) is held per ractor, so ;TI"Bractors are performed in parallel without locking each other.;T@o;;[I"aInstead of accessing the shared state, the objects should be passed to and from ractors via ;TI"/sending and receiving objects as messages.;T@o; ;[ I"a = 1 ;TI"r = Ractor.new do ;TI"N a_in_ractor = receive # receive blocks till somebody will pass message ;TI"/ puts "I am in Ractor! a=#{a_in_ractor}" ;TI" end ;TI"r.send(a) # pass it ;TI"r.take ;TI"3# here "I am in Ractor! a=1" would be printed ;T;0o;;[I"CThere are two pairs of methods for sending/receiving messages:;T@o:RDoc::Markup::List: @type:BULLET:@items[o:RDoc::Markup::ListItem:@label0;[o;;[I"TRactor#send and Ractor.receive for when the _sender_ knows the receiver (push);;To;;0;[o;;[I"RRactor.yield and Ractor#take for when the _receiver_ knows the sender (pull);;T@o;;[I"aIn addition to that, an argument to Ractor.new would be passed to block and available there ;TI"]as if received by Ractor.receive, and the last block value would be sent outside of the ;TI"'ractor as if sent by Ractor.yield.;T@o;;[I"3A little demonstration on a classic ping-pong:;T@o; ;[I"server = Ractor.new do ;TI"- puts "Server starts: #{self.inspect}" ;TI"! puts "Server sends: ping" ;TI"x Ractor.yield 'ping' # The server doesn't know the receiver and sends to whoever interested ;TI"u received = Ractor.receive # The server doesn't know the sender and receives from whoever sent ;TI"+ puts "Server received: #{received}" ;TI" end ;TI" ;TI"jclient = Ractor.new(server) do |srv| # The server is sent inside client, and available as srv ;TI"- puts "Client starts: #{self.inspect}" ;TI"k received = srv.take # The Client takes a message specifically from the server ;TI"& puts "Client received from " \ ;TI"* "#{srv.inspect}: #{received}" ;TI"! puts "Client sends to " \ ;TI"# "#{srv.inspect}: pong" ;TI"i srv.send 'pong' # The client sends a message specifically to the server ;TI" end ;TI" ;TI"N[client, server].each(&:take) # Wait till they both finish ;T;0o;;[I"This will output:;T@o; ;[I"3Server starts: #<Ractor:#2 test.rb:1 running> ;TI"Server sends: ping ;TI"3Client starts: #<Ractor:#3 test.rb:8 running> ;TI"?Client received from #<Ractor:#2 rac.rb:1 blocking>: ping ;TI":Client sends to #<Ractor:#2 rac.rb:1 blocking>: pong ;TI"Server received: pong ;T;0o;;[ I"]It is said that Ractor receives messages via the <em>incoming port</em>, and sends them ;TI"^to the <em>outgoing port</em>. Either one can be disabled with Ractor#close_incoming and ;TI"ZRactor#close_outgoing respectively. If a ractor terminated, its ports will be closed ;TI"automatically.;T@S:RDoc::Markup::Heading: leveli: textI"&Shareable and unshareable objects;T@o;;[I"_When the object is sent to and from the ractor, it is important to understand whether the ;TI"Qobject is shareable or unshareable. Most of objects are unshareable objects.;T@o;;[I"eShareable objects are basically those which can be used by several threads without compromising ;TI"kthread-safety; e.g. immutable ones. Ractor.shareable? allows to check this, and Ractor.make_shareable ;TI"1tries to make object shareable if it is not.;T@o; ;[I"^Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are ;TI"rRactor.shareable?('foo') #=> false, unless the string is frozen due to # freeze_string_literals: true ;TI".Ractor.shareable?('foo'.freeze) #=> true ;TI" ;TI"ary = ['hello', 'world'] ;TI"+ary.frozen? #=> false ;TI"+ary[0].frozen? #=> false ;TI" Ractor.make_shareable(ary) ;TI"*ary.frozen? #=> true ;TI"*ary[0].frozen? #=> true ;TI"*ary[1].frozen? #=> true ;T;0o;;[ I"dWhen a shareable object is sent (via #send or Ractor.yield), no additional processing happens, ;TI"_and it just becomes usable by both ractors. When an unshareable object is sent, it can be ;TI"beither _copied_ or _moved_. The first is the default, and it makes the object's full copy by ;TI":deep cloning of non-shareable parts of its structure.;T@o; ;[ I""data = ['foo', 'bar'.freeze] ;TI"r = Ractor.new do ;TI" data2 = Ractor.receive ;TI"Z puts "In ractor: #{data2.object_id}, #{data2[0].object_id}, #{data2[1].object_id}" ;TI" end ;TI"r.send(data) ;TI"r.take ;TI"Uputs "Outside : #{data.object_id}, #{data[0].object_id}, #{data[1].object_id}" ;T;0o;;[I"This will output:;T@o; ;[I"In ractor: 340, 360, 320 ;TI"Outside : 380, 400, 320 ;T;0o;;[I"_(Note that object id of both array and non-frozen string inside array have changed inside ;TI"]the ractor, showing it is different objects. But the second array's element, which is a ;TI"6shareable frozen string, has the same object_id.);T@o;;[I"WDeep cloning of the objects may be slow, and sometimes impossible. Alternatively, ;TI"[<tt>move: true</tt> may be used on sending. This will <em>move</em> the object to the ;TI"Creceiving ractor, making it inaccessible for a sending ractor.;T@o; ;[I"data = ['foo', 'bar'] ;TI"r = Ractor.new do ;TI"' data_in_ractor = Ractor.receive ;TI"U puts "In ractor: #{data_in_ractor.object_id}, #{data_in_ractor[0].object_id}" ;TI" end ;TI"r.send(data, move: true) ;TI"r.take ;TI"<puts "Outside: moved? #{Ractor::MovedObject === data}" ;TI"%puts "Outside: #{data.inspect}" ;T;0o;;[I"This will output:;T@o; ;[I"In ractor: 100, 120 ;TI"Outside: moved? true ;TI"dtest.rb:9:in `method_missing': can not send any methods to a moved object (Ractor::MovedError) ;T;0o;;[I"^Notice that even +inspect+ (and more basic methods like <tt>__id__</tt>) is inaccessible ;TI"on a moved object.;T@o;;[ I"dBesides frozen objects, there are shareable objects. Class and Module objects are shareable so ;TI"hthe Class/Module definitons are shared between ractors. Ractor objects are also shareable objects. ;TI"eAll operations for the shareable mutable objects are thread-safe, so the thread-safety property ;TI"lwill be kept. We can not define mutable shareable objects in Ruby, but C extensions can introduce them.;T@o;;[I"qIt is prohibited to access instance variables of mutable shareable objects (especially Modules and classes) ;TI""from ractors other than main:;T@o; ;[I" class C ;TI" class << self ;TI" attr_accessor :tricky ;TI" end ;TI" end ;TI" ;TI"C.tricky = 'test' ;TI" ;TI" r = Ractor.new(C) do |cls| ;TI" puts "I see #{cls}" ;TI"( puts "I can't see #{cls.tricky}" ;TI" end ;TI"r.take ;TI"# I see C ;TI"a# can not access instance variables of classes/modules from non-main Ractors (RuntimeError) ;T;0o;;[I"bRactors can access constants if they are shareable. The main Ractor is the only one that can ;TI"$access non-shareable constants.;T@o; ;[I"GOOD = 'good'.freeze ;TI"BAD = 'bad' ;TI" ;TI"r = Ractor.new do ;TI" puts "GOOD=#{GOOD}" ;TI" puts "BAD=#{BAD}" ;TI" end ;TI"r.take ;TI"# GOOD=good ;TI"d# can not access non-shareable objects in constant Object::BAD by non-main Ractor. (NameError) ;TI" ;TI",# Consider the same C class from above ;TI" ;TI"r = Ractor.new do ;TI" puts "I see #{C}" ;TI"& puts "I can't see #{C.tricky}" ;TI" end ;TI"r.take ;TI"# I see C ;TI"a# can not access instance variables of classes/modules from non-main Ractors (RuntimeError) ;T;0o;;[I"OSee also the description of <tt># shareable_constant_value</tt> pragma in ;TI"F{Comments syntax}[rdoc-ref:doc/syntax/comments.rdoc] explanation.;T@S;;i;I"Ractors vs threads;T@o;;[I"WEach ractor creates its own thread. New threads can be created from inside ractor ;TI"D(and, on CRuby, sharing GVL with other threads of this ractor).;T@o; ;[I"r = Ractor.new do ;TI" a = 1 ;TI"9 Thread.new {puts "Thread in ractor: a=#{a}"}.join ;TI" end ;TI"r.take ;TI"4# Here "Thread in ractor: a=1" will be printed ;T;0S;;i;I"Note on code examples;T@o;;[I"XIn examples below, sometimes we use the following method to wait till ractors that ;TI"Rare not currently blocked will finish (or process till next blocking) method.;T@o; ;[I"def wait ;TI" sleep(0.1) ;TI" end ;T;0o;;[I"UIt is **only for demonstration purposes** and shouldn't be used in a real code. ;TI"KMost of the times, just #take is used to wait till ractor will finish.;T@S;;i;I"Reference;T@o;;[I"FSee {Ractor desgin doc}[rdoc-ref:doc/ractor.md] for more details.;T; I"ractor.rb;T; 0; 0; 0[ [ [ [[I" class;T[[:public[[I" count;TI"ractor.rb;T[I"current;T@-[I" main;T@-[I"make_shareable;T@-[I"new;T@-[I"receive;T@-[I"receive_if;T@-[I" recv;T@-[I"select;T@-[I"shareable?;T@-[I" yield;T@-[:protected[ [:private[ [I" instance;T[[;[[I"<<;T@-[I"[];T@-[I"[]=;T@-[I"close_incoming;T@-[I"close_outgoing;T@-[I"inspect;T@-[I" name;T@-[I" recv;T@-[I" send;T@-[I" take;T@-[I" to_s;T@-[;[ [;[[I"receive;T@-[I"receive_if;T@-[ [U:RDoc::Context::Section[i 0o;;[ ; 0; 0[@ @!@!cRDoc::TopLevel