هل ستزيد متعدد الخيوط من أداء طريقة في خدمة WCF؟

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

سؤال

لدي خدمة WCF التي تم استضافتها في IIS6. الجزء المهم من الطريقة يبدو هكذا:

public MyUser[] GetUsers(string appName, string[] names)
{
    List<User> users = new List<User>();
    foreach (string user in names)
    {
      MembershipUser mu = this.ADAMProvider.GetUser(user, false);  //Unmanaged call to AzMan
      if (mu != null)
      {
        users.Add(MyUser.CreateFrom(mu);
      }
    }
    return users.ToArray();
}

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

لزيادة الأداء أنا أفكر في نهج متعدد الخيوط. .NET 4 ليس خيارًا متوازيًا. بالنسبة إلى ليس خيارًا ولكن القيام بما يعادله في 3.5 هو.

سؤالي هو إنشاء مجموعة من المواضيع (ثم في انتظار كل شيء قبل العودة) زيادة في الواقع؟ هل هناك خطر في القيام بذلك في خدمة WCF المستضافة IIS6؟

هل كانت مفيدة؟

المحلول

أولاً ، أشير إلى أن مكون COM يمكن أن يكون مشكلة اعتمادًا على حالته الشقت. يمكن تشغيل كائنات الشقة ذات الخيوط الواحدة فقط في مؤشر ترابط واحد. هناك عملية تلقائية تلقائية تحدث على كائنات STA التي من شأنها أن تتصرف بشكل فعال بجميع المكالمات إليها ، لذا بغض النظر عن مدى صعوبة تجربتك مايو لا تحصل على أي موازٍ. حتى لو كان كائن MTA ، فقد تكون هناك مشكلة في GetUser الطريقة إذا لم يتم تصميمها لتكون آمنة مؤشرات الترابط.

لكن على افتراض أن أيًا من هذا يمثل مشكلة1 أود استخدام ThreadPool بدلاً من إنشاء مجموعة من المواضيع للقيام بذلك. هنا هو ما قد يبدو.

public MyUser[] GetUsers(string appName, string[] names) 
{ 
  int count = 1; // Holds the number of pending work items.
  var finished = new ManualResetEvent(false); // Used to wait for all work items to complete.
  var users = new List<User>(); 
  foreach (string user in names) 
  {
    Interlocked.Increment(ref count); // Indicate that we have another work item.
    ThreadPool.QueueUserWorkItem(
      (state) =>
      { 
        try
        {
          MembershipUser mu = this.ADAMProvider.GetUser(user, false); 
          if (mu != null) 
          { 
            lock (users)
            {
              users.Add(MyUser.CreateFrom(mu); 
            }
          } 
        }
        finally
        {
          // Signal the event if this is the last work item.
          if (Interlocked.Decrement(ref count) == 0) finished.Set();
        }
      });
  } 
  // Signal the event if this is the last work item.
  if (Interlocked.Decrement(ref count) == 0) finished.Set();
  // Wait for all work items to complete.
  finished.WaitOne();
  return users.ToArray(); 
}

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

بالمناسبة ، أود أن أشير إلى أن TPL متاح في .NET 3.5 كجزء من الامتدادات التفاعلية تحميل.

1أظن أن إحدى المشكلتين اللتين ذكرتهما سيكون في اللعب في الواقع.

نصائح أخرى

عادة ، أقول إن هذا قد يساعد - ومع ذلك ، سيكون هذا مصدر قلق:

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

هذا يبدو أن مكون "Azman" ليس آمنًا. إذا كان هذا هو الحال ، فلن يكون من الممكن أن يعدد هذا الروتين بشكل فعال ، لأنه يقضي معظم وقته في هذا الروتين.

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

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