سؤال

كنت دائما أسمع أن رمز وظيفي بطبيعتها أسهل يوازي من غير وظيفية رمز, لذلك قررت أن أكتب وظيفة يفعل ما يلي:

إعطاء المدخلات من سلاسل, إجمالي عدد أحرف فريدة من نوعها لكل سلسلة.وذلك نظرا الإدخال [ "aaaaa"; "bbb"; "ccccccc"; "abbbc" ], لدينا طريقة سوف يعود a: 6; b: 6; c: 8.

هنا ما كنت قد كتبت:

(* seq<#seq<char>> -> Map<char,int> *)
let wordFrequency input =
    input
    |> Seq.fold (fun acc text ->
        (* This inner loop can be processed on its own thread *)
        text
        |> Seq.choose (fun char -> if Char.IsLetter char then Some(char) else None)
        |> Seq.fold (fun (acc : Map<_,_>) item ->
            match acc.TryFind(item) with
            | Some(count) -> acc.Add(item, count + 1)
            | None -> acc.Add(item, 1))
            acc
        ) Map.empty

هذا الرمز هو مثالي parallelizable ، لأن كل سلسلة في input يمكن معالجتها في موضوع خاص بها.ليست بسيطة كما يبدو منذ innerloop يضيف بنود خارطة مشترك بين كل من المدخلات.

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

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

المحلول

كما أشار بالفعل هناك تحديث الخلاف إذا كنت تحاول الحصول المواضيع المختلفة عملية الإدخال المختلفة سلاسل, لأن كل موضوع يمكن زيادة العدد من كل رسالة.هل يمكن أن يكون كل موضوع في إنتاج الخرائط الخاصة بها ، ومن ثم إضافة ما يصل جميع خرائط ، ولكن تلك الخطوة النهائية قد تكون مكلفة (و ليست مناسبة تماما إلى الاستفادة من المواضيع بسبب البيانات المشتركة).أعتقد كبيرة المدخلات من المرجح أن تعمل بشكل أسرع باستخدام خوارزمية مثل واحد أدناه ، حيث كل موضوع عمليات مختلفة الرسالة إلى عدد (لجميع السلاسل في المدخلات).ونتيجة لذلك, كل موضوع له دولته المستقلة العداد حتى لا تحديث الخلاف لا الخطوة الأخيرة إلى الجمع بين النتائج.ومع ذلك نحن بحاجة تجهيزها إلى اكتشاف مجموعة من رسائل فريدة من نوعها' ، و هذه الخطوة لا يكون نفس الخلاف المشكلة.(في الواقع, ربما كنت أعرف الكون من الشخصيات الجبهة مثلا ، alphabetics ، ومن ثم يمكن فقط يخلق 26 المواضيع العملية a-z, وتجاوز هذه المسألة.) في أي حال ، ويفترض السؤال هو الغالب حول استكشاف كيفية كتابة F# المتزامن قانون لتقسيم العمل في جميع المواضيع ، لذلك رمز أدناه يوضح ذلك.

#light

let input = [| "aaaaa"; "bbb"; "ccccccc"; "abbbc" |]

// first discover all unique letters used
let Letters str = 
    str |> Seq.fold (fun set c -> Set.add c set) Set.empty 
let allLetters = 
    input |> Array.map (fun str -> 
        async { return Letters str })
    |> Async.Parallel 
    |> Async.Run     
    |> Set.union_all // note, this step is single-threaded, 
        // if input has many strings, can improve this

// Now count each letter on a separate thread
let CountLetter letter =
    let mutable count = 0
    for str in input do
        for c in str do
            if letter = c then
                count <- count + 1
    letter, count
let result = 
    allLetters |> Seq.map (fun c ->
        async { return CountLetter c })
    |> Async.Parallel 
    |> Async.Run

// print results
for letter,count in result do
    printfn "%c : %d" letter count

أنا بالفعل 'تغير تماما خوارزمية', في الغالب لأنني الأصلي خوارزمية كان لديك لا سيما مناسبة لتوجيه البيانات الموازاة بسبب التحديث الخلاف.اعتمادا على بالضبط ما كنت تعلم أن هذا الجواب قد أو قد لا تكون مرضية لك.

نصائح أخرى

يمكنك كتابة مثل هذا:

let wordFrequency =
  Seq.concat >> Seq.filter System.Char.IsLetter >> Seq.countBy id >> Map.ofSeq

وما يوازي ذلك مع اثنين فقط من الأحرف الزائدة إلى استخدام PSeq وحدة من FSharp.PowerPack.Parallel.Seq DLL بدلا من العادية Seq الوحدة النمطية:

let wordFrequency =
  Seq.concat >> PSeq.filter System.Char.IsLetter >> PSeq.countBy id >> Map.ofSeq

على سبيل المثال ، فإن الوقت الذي يستغرقه حساب الترددات من 5.5 Mb الملك جيمس الكتاب المقدس يسقط من 4.75 s 0.66 s.هذا هو 7.2× تسريع على هذا 8-آلة الأساسية.

موازية ليس هو نفسه كما المتزامن ، لا يفسر سايم.

لذا المنظمة البحرية الدولية ستكون أفضل حالا باستخدام PLINQ إلى يوازي.

أنا لا أتكلم F# في كل شيء بشكل جيد, ولكن لا يمكن معالجة هذا.التفكير في استخدام الخريطة/الحد:

السماح n = بطاقة(ص) يكون عدد الرموز σ في الأبجدية Σ.

خريطة المرحلة:

تفرخ n العمليات ، حيث تعيين أنا-ال عملية رصيده إلى عدد من الحوادث من الرمز σأنا في كل ناقلات المدخلات.

والحد من المرحلة:

جمع الكلي لكل من n العمليات في النظام.أن ناقلات النتائج الخاصة بك.

الآن, هذا الإصدار لا يؤدي إلى أي تحسن على المسلسل الإصدار ؛ وأظن أن هناك يختبئ التبعية هنا أن يجعل هذا أصلا من الصعب يوازي ولكن أنا متعب جدا و الدماغ الميت لاثبات ذلك الليلة.

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