如何在Ada中多次调用任务

时间:2019-06-03 09:59:38

标签: loops task ada

我尝试调用一个任务100次,但是它不起作用,看来我应该创建100个条目来执行此操作。所以,请您提供一些建议吗?

我正在学习如何使用Ada任务:-)

explain (analyze, verbose)
select *
  from generate_series(1,50000) AS w
  cross join generate_series(current_date,current_date+30,interval '1 day') AS v;

QUERY PLAN
Nested Loop  (cost=0.02..20010.02 rows=1000000 width=12) (actual time=3.237..3128.123 rows=1550000 loops=1)
  Output: w.w, v.v
  ->  Function Scan on pg_catalog.generate_series w  (cost=0.00..10.00 rows=1000 width=4) (actual time=3.210..35.472 rows=50000 loops=1)
        Output: w.w
        Function Call: generate_series(1, 50000)
  ->  Function Scan on pg_catalog.generate_series v  (cost=0.02..10.02 rows=1000 width=8) (actual time=0.001..0.021 rows=31 loops=50000)
        Output: v.v
        Function Call: generate_series((('now'::cstring)::date)::timestamp with time zone, ((('now'::cstring)::date + 30))::timestamp with time zone, '1 day'::interval)
Planning time: 0.046 ms
Execution time: 4103.113 ms

E:\ Ada代码\ Simple \ obj \ main.exe 哈哈

提高了TASKING_ERROR [2019-06-03 17:55:17]进程退出,状态为1,经过时间:01.00s

2 个答案:

答案 0 :(得分:3)

您的问题是任务将在接受第一个集合点后运行到完成。您可以通过在任务正文中添加循环来避免这种情况:

task body test1 is
begin
   loop
      accept start;
      Put_Line("Haha");
   end loop;
end test1;

(实际上,大多数任务都会有这样的循环)

该任务现在具有无限循环,因此下一步是确保您的任务在主程序完成后终止。在这种情况下,您可以使用选择性接受

task body test1 is
begin
   loop
      select
         accept start;
      or
         terminate;
      end select;

      Put_Line("Haha");
   end loop;
end test1;

答案 1 :(得分:2)

通常,与启动另一个任务相比,调用任务条目,将任何所需的数据传入或传出任务比调用另一个任务效率更高。开始和终止任务涉及不小的开销。 为任务调用任务条目的另一种方法是使用受保护的对象实现生产者-消费者模式。

以下生产者-消费者示例创建三个生产者和一个消费者。每个生产者将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;

如您所见,使用者一直运行直到所有数据被消耗为止,而不知道有多少生产者正在运行或有多少消息正在产生。这比让每个生产者为产生的每条消息都呼叫一个消费者要有效得多。