نمط للحد من عدد المكالمات غير المتزامنة في وقت واحد

StackOverflow https://stackoverflow.com/questions/2605194

سؤال

أحتاج إلى استرداد كائنات متعددة من نظام خارجي. يدعم النظام الخارجي طلبات متعددة متزامنة (IE Threads) ، ولكن من الممكن إغراق النظام الخارجي - لذلك أريد أن أكون قادرًا على استرداد كائنات متعددة بشكل غير متزامن ، لكنني أريد أن أكون قادرًا على خنق عدد الطلبات غير المتزامنة المتزامنة. أي أحتاج إلى استرداد 100 عنصر ، لكن لا أريد أن أكون الاسترداد أكثر من 25 منهم في وقت واحد. عند اكتمال كل طلب من 25 عامًا ، أريد أن أشعل استرجاعًا آخر ، وبمجرد اكتماله جميعًا ، أرغب في إعادة جميع النتائج بالترتيب الذي تم طلبه (أي ليس هناك فائدة من إرجاع النتائج حتى يتم إرجاع المكالمة بأكملها ). هل هناك أي أنماط موصى بها لهذا النوع من الأشياء؟

هل سيكون شيء من هذا القبيل مناسبًا (رمز كاذب ، من الواضح)؟

  private List<externalSystemObjects> returnedObjects = new List<externalSystemObjects>;

  public List<externalSystemObjects> GetObjects(List<string> ids)
  {
      int callCount = 0;
      int maxCallCount = 25;
      WaitHandle[] handles;

      foreach(id in itemIds to get)
      {
          if(callCount < maxCallCount)
          {
               WaitHandle handle = executeCall(id, callback);
               addWaitHandleToWaitArray(handle)
          }
      else
      {
           int returnedCallId = WaitHandle.WaitAny(handles);
           removeReturnedCallFromWaitHandles(handles);
      }
   }

   WaitHandle.WaitAll(handles);

   return returnedObjects;
   }

   public void callback(object result)
   {
         returnedObjects.Add(result);
   }
هل كانت مفيدة؟

المحلول

ضع في اعتبارك قائمة العناصر التي يجب معالجتها كقائمة انتظار يتم من خلالها 25 مؤشر ترابط معالجة المهام ، معالجة مهمة ، أضف النتيجة ثم كررها حتى تصبح قائمة الانتظار فارغة:

 class Program
  {
    class State
    {
      public EventWaitHandle Done;
      public int runningThreads;
      public List<string> itemsToProcess;
      public List<string> itemsResponses;
    }

    static void Main(string[] args)
    {
      State state = new State();

      state.itemsResponses = new List<string>(1000);
      state.itemsToProcess = new List<string>(1000);
      for (int i = 0; i < 1000; ++i)
      {
        state.itemsToProcess.Add(String.Format("Request {0}", i));
      }

      state.runningThreads = 25;
      state.Done = new AutoResetEvent(false);

      for (int i = 0; i < 25; ++i)
      {
        Thread t =new Thread(new ParameterizedThreadStart(Processing));
        t.Start(state);
      }

      state.Done.WaitOne();

      foreach (string s in state.itemsResponses)
      {
        Console.WriteLine("{0}", s);
      }
    }

    private static void Processing(object param)
    {
      Debug.Assert(param is State);
      State state = param as State;

      try
      {
        do
        {
          string item = null;
          lock (state.itemsToProcess)
          {
            if (state.itemsToProcess.Count > 0)
            {
              item = state.itemsToProcess[0];
              state.itemsToProcess.RemoveAt(0);
            }
          }
          if (null == item)
          {
            break;
          }
          // Simulate some processing
          Thread.Sleep(10);
          string response = String.Format("Response for {0} on thread: {1}", item, Thread.CurrentThread.ManagedThreadId);
          lock (state.itemsResponses)
          {
            state.itemsResponses.Add(response);
          }
        } while (true);

      }
      catch (Exception)
      {
        // ...
      }
      finally
      {
        int threadsLeft = Interlocked.Decrement(ref state.runningThreads);
        if (0 == threadsLeft)
        {
          state.Done.Set();
        }
      }
    }
  }

يمكنك أن تفعل الشيء نفسه باستخدام عمليات الاسترجاعات غير المتزامنة ، ليست هناك حاجة لاستخدام مؤشرات الترابط.

نصائح أخرى

يعد وجود بنية تشبه قائمة الانتظار للاحتفاظ بطلبات المعلقة نمطًا شائعًا جدًا. في تطبيقات الويب حيث قد يكون هناك عدة طبقات من المعالجة ، ترى نهجًا على نمط "قمع" مع الأجزاء المبكرة من تغيير المعالجة لها قوائم قوائم أكبر. قد يكون هناك أيضًا نوع من تحديد الأولويات المطبق على قوائم الانتظار ، وطلبات الأولوية الأعلى يتم خلطها إلى أعلى قائمة الانتظار.

أحد الأشياء المهمة التي يجب مراعاتها في الحل الخاص بك هو أنه إذا كان معدل وصول الطلب أعلى من معدل المعالجة الخاص بك (قد يكون هذا بسبب رفض رفض الخدمة ، أو أن جزءًا من المعالجة بطيء بشكل غير عادي اليوم) بدون ملزم. يجب أن يكون لديك بعض السياسة مثل رفض الطلبات الجديدة فورًا عندما يتجاوز عمق قائمة الانتظار بعض القيمة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top