Как правило, более эффективно вызывать запись задачи, передавая любые необходимые данные в задачу или из нее, чем запускать другую задачу. Нетривиальные издержки, связанные с запуском и завершением задачи.
Альтернативой вызову записей задач для задач является реализация шаблона производитель-потребитель с использованием защищенных объектов.
Следующий пример производитель-потребитель создает трех производителей и одного потребителя. Каждый из производителей записывает 500 000 сообщений в общую очередь. Потребитель потребляет все сообщения, произведенные производителями.
------------------------------------------------------------------
-- Producer / Consumer example using 3 producers and 1 consumer --
-- Matches the number of tasks to a 4-core processor --
------------------------------------------------------------------
with Ada.Containers.Synchronized_Queue_Interfaces;
with Ada.Containers.Unbounded_Synchronized_Queues;
with Ada.Text_IO; use Ada.Text_IO;
With Ada.Calendar; use Ada.Calendar;
use Ada.Containers;
procedure PC_v3 is
package Integer_Interface is new
Synchronized_Queue_Interfaces(Element_Type => Integer);
package Unbounded_Integer_Queues is new
Unbounded_Synchronized_Queues(Queue_Interfaces => Integer_Interface);
My_Queue : Unbounded_Integer_Queues.Queue;
Num_Producers : Constant := 3;
Max_Produced : constant := 500_000;
Empty_Queue : constant Count_Type := 0;
Start_Time : Time := Clock;
-- The Counter protected object below is used to count the number of
-- completed producers. This allows the consumer to know when all the
-- data has been processed.
---------------------------------------------------------------------
protected Counter is
Procedure Task_Done;
function All_Done return boolean;
private
Count : Natural := 0;
end Counter;
protected body Counter is
procedure Task_Done is
begin
Count := Count + 1;
end Task_Done;
function All_Done return boolean is
begin
return Count = Num_Producers;
end All_Done;
end Counter;
-- Define the producer task type.
-- Producer is being defined as a task type to allow multiple instances
-- of the producer to be easily created.
------------------------------------------------------------------------
task type Producer;
Task body Producer is
Value : Positive := 1;
Finis_Time : Time;
begin
loop
My_Queue.Enqueue(Value);
Value := Value + 1;
if Value > Max_Produced then
Counter.Task_Done;
Finis_Time := Clock;
Put_Line("Producer completed in" &
Duration'Image(Finis_Time - Start_Time) &
" seconds");
exit; -- exit the loop within the Producer task
end if;
end loop;
end Producer;
Read_Value : Integer;
Done_Time : Time;
-- Create an array of producers. There are Num_Producers in this
-- array. The Producer tasks start executing as soon as they are
-- instantiated in the array.
----------------------------------------------------------------
The_Producers : array(1..Num_Producers) of Producer;
begin
-- Process the values in My_Queue until all producers are completed
-- and the queue is empty.
-- The program main task is being used as the consumer task.
loop
My_Queue.Dequeue(Read_Value);
exit when Counter.All_Done and then My_Queue.Current_Use = Empty_Queue;
end loop;
-- Record the time stamp when all queue processing is done
Done_Time := Clock;
-- print out the execution statistics
Put_Line("Queue element peak use:" & Count_Type'Image(My_Queue.Peak_Use));
Put_Line("Elapsed time (seconds):" & Duration'Image(Done_Time - Start_Time));
end PC_V3;
Как видите, потребитель продолжает работать до тех пор, пока не будут использованы все данные, не зная, сколько производителей работает или сколько сообщений генерируется. Это гораздо эффективнее, чем когда каждый производитель звонит потребителю для каждого созданного сообщения.