سؤال

أنا جديد على C#، Parallel.ForEach, و .NET بشكل عام.أريد موازنة البحث الذي يتضمن آلاف المواقع.لكل موقع، أحسب مسافة دائرة كبيرة.هذا هو الحساب الذي أريد نشره على نوى مختلفة.سؤالي هو كيف أفعل ذلك إذا كان لدي فقط واحد متغير مؤشر الترابط المحلي، كما في هذا مثال MSDN TPL؟بالنسبة للنتيجة، نظرت إلى Interlocked, ، ورأيت خياراته Add, CompareExchange, Decrement, Exchange, Increment و Read, ، لكنني لا أقوم فقط بإضافة أو زيادة أو إنقاص أو اختبار المساواة.أريد إرجاع الكائن، عبر عدة سلاسل تعمل بالتوازي، والذي يحتوي على الأقصر إجمالي مسافة.حدسي يقول أن هذا يجب أن يكون سهلاً، وأنني يجب أن أكون قادرًا على إنشاء بعض الأشياء الصغيرة التي تلتف Location والمسافة، ولكن كيف يمكنني الحصول على أفضل إجابة من كل موضوع و ثم اختر أقصر مسافة بينهم؟هنا هو الإصدار غير الموازي:

Location findClosestLocation(Location myLocation, List<Location> allLocations)
{
  double closest = double.MaxValue;
  Location closestLoc = null;
  foreach (Location aLoc in allLocations)
  {
    if (aLoc != myLocation)
    {
      double d = greatCircle(myLocation, aLoc);
      if (d < closest)
      {
        closest = d;
        closestLoc = aLoc;
      }
    }
  }
  return closestLoc;
}

لقد رأيت أ مشاركة مدونة DDJ يبدو أن هذا يقدم نصيحة جيدة، لكنني تساءلت عما إذا كانت أفضل نصيحة.أرى المؤلف يكرر المصفوفات، وأتساءل عما إذا لم تكن هناك طريقة أكثر وظيفية للقيام بذلك.في العالم الوظيفي سأستخدمه map, lambda و min.

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

المحلول

الخيار الأسهل هنا هو التبديل إلى PLINQ:

Location findClosestLocation(Location myLocation, List<Location> allLocations)
{
     return allLocations
               .AsParallel()
               .Min(location => greatCircle(myLocation, location));
}

ومع ذلك، هذا هو في الأساس مجرد التجميع مع بنيات متوازية.لديك خياران إذا كنت تريد الالتزام بالفئة الموازية.أحد الخيارات هو مزامنة ذلك بنفسك داخل الكتلة باستخدام القفل.لا أوصي بهذا لأنه سيضر بأدائك العام.

الخيار الأفضل هو استخدام Parallel.ForEach الأساليب التي توفر الدولة المحلية.سيسمحون لك بإعادة كتابة هذا على النحو التالي:

Location findClosestLocation(Location myLocation, List<Location> allLocations)
{
  double closest = double.MaxValue;
  Location closestLoc = null;
  object sync = new object();

  Parallel.ForEach<Location, Tuple<double,Location>(
      allLocations,
      () => new Tuple(double.MaxValue, null),
      (location, loopState, localState) =>
      {
          double d = greatCircle(myLocation, aLoc);
          if (d < localState.Item1)
              return new Tuple(d, aLoc);
          else
              return localState;
      },
      localState =>
      {
          lock(sync)
          {
              if (localState.Item1 < closest)
              {
                  closest = localState.Item1;
                  closestLoc = localState.Item2;
              }
          }
      }
  );
  return closestLoc;
}

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

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