سؤال

المشكلة: لقد ضخمة الخام ملف نصي (نفترض من 3gig), كنت بحاجة إلى الذهاب من خلال كل كلمة في الملف و تجد أن كلمة يظهر كيف مرات عديدة في الملف.

بلدي الحل المقترح: تقسيم ضخمة الملف إلى عدة ملفات و كل انقسم سيكون الملف الكلمات في فرز الطريقة.على سبيل المثال ، جميع الكلمات التي تبدأ مع "a"سيتم تخزينها في "_a.dic"الملف.لذلك في أي وقت ونحن لن execeed أكثر من 26 الملفات.

المشكلة في هذا النهج ،

يمكنني استخدام تيارات قراءة الملف ولكن أردت استخدام المواضيع قراءة أجزاء معينة من ملف.على سبيل المثال قراءة 0-1024 بايت مع موضوع مستقل (على الأقل يكون 4-8 المواضيع على أساس لا.المعالجات موجودة في المربع).هل هذا ممكن أم أنني أحلم ؟

أي أفضل النهج ؟

ملاحظة:يجب أن تكون نقية c++ أو c على أساس الحل.لا قواعد البيانات وما إلى ذلك ، مسموح بها.

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

المحلول

تحتاج إلى إلقاء نظرةممارسة البرمجة قبل كيرنيغان و رمح و تحديدا الفصل 3.

في C++, استخدام الخريطة على أساس سلاسل العد (std::map<string,size_t>, IIRC).قراءة الملف (مرة واحدة - انها كبيرة جدا إلى قراءة أكثر من مرة واحدة) ، تقسيمه إلى الكلمات كما تذهب (لبعض تعريف 'كلمة'), و تزايد العدد في الخريطة دخول كل كلمة تجد.

في C, سيكون لديك لإنشاء الخريطة نفسك.(أو العثور على ديفيد هانسون "ج واجهات تطبيقات".)

أو يمكنك استخدام بيرل أو بايثون ، أو Awk (التي صفائف النقابي ، أي ما يعادل الخريطة).

نصائح أخرى

لا أعتقد أن استخدام مؤشرات ترابط متعددة أن قراءة أجزاء من الملف في موازاة ذلك سوف يساعد كثيرا.أتوقع أن هذا التطبيق هو لا بد أن عرض النطاق الترددي و الكمون من القرص الصلب لا الفعلي كلمة العد.هذه متعددة الخيوط النسخة قد تؤدي في الواقع أسوأ من ذلك لأن "شبه عشوائية" الوصول إلى الملفات عادة أبطأ من "خطي الملف" الوصول.

في حالة وحدة المعالجة المركزية هو مشغول في واحدة مترابطة الإصدار قد يكون هناك احتمال تسريع.موضوع واحد يمكن قراءة البيانات في مساحات كبيرة ووضعها في طابور من قدرة محدودة.مجموعة من المواضيع عامل يمكن أن تعمل كل من تلقاء نفسها قطعة و عد الكلمات.بعد فرز المواضيع عامل الانتهاء يجب عليك دمج كلمة العدادات.

أولا - اتخاذ قرار بشأن datastructure لحفظ الكلمات.

الخيار الواضح هو الخريطة.ولكن ربما Trie أن أفضل خدمة لكم.في كل عقدة حفظ الاعتماد على الكلمة.0 يعني أنه فقط جزء من كلمة.يمكنك إدراج في trie باستخدام تيار من قراءة الملف characterbased.

الثانية - خاصية تعدد نعم أو لا ؟ هذا ليس من السهل الإجابة.اعتمادا على حجم datastructure ينمو وكيف يوازي الجواب قد تختلف.

  1. Singlethreaded - straitforward وسهلة التنفيذ.
  2. مؤشرات متعددة القارئ المواضيع واحد datastructur.ثم لديك لمزامنة الوصول إلى datastructure.في Trie ، تحتاج فقط إلى قفل العقدة كنت فعلا في ذلك متعددة يمكن للقراء الوصول إلى datastructure دون تدخل.الذاتي موازنة شجرة قد تكون مختلفة ، وخاصة عند إعادة التوازن.
  3. مؤشرات متعددة المواضيع القارئ ، كل مع الخاصة بهم datastructure.كل موضوع يبني نفسه datastructure أثناء قراءة جزء من الملف.بعد كل واحد انتهى ، فإن النتائج يجب أن تكون جنبا إلى جنب (التي ينبغي أن تكون سهلة).

شيء واحد عليك أن تفكر - عليك أن تجد كلمة الحدود لكل موضوع البدء ، ولكن هذا يجب أن لا تشكل مشكلة كبيرة (مثلا ، كل موضوع يمشي انها تبدأ حتى أول كلمة الحدود ويبدأ هناك في نهاية كل موضوع التشطيبات كلمة انها تعمل على).

في حين يمكنك استخدام الخيط الثاني لتحليل البيانات بعد قراءة ذلك, كنت على الارجح لن الحصول على كمية كبيرة من القيام بذلك.محاولة استخدام مؤشر ترابط واحد أو أكثر من قراءة البيانات يكاد يكون من المؤكد سوف يضر السرعة بدلا من تحسينها.استخدام مؤشرات ترابط متعددة لمعالجة البيانات لا طائل-تجهيز سوف يكون أسرع عدة مرات من القراءة حتى مع إضافي واحد فقط موضوع الحد ستكون سرعة القرص.

واحد (ممكن) طريقة للحصول على سرعة كبيرة لتجاوز المعتاد iostreams -- في حين أن بعض تقريبا بأسرع باستخدام C الملف*'s, أنا لا أعرف أي شيء حقا أسرع ، وبعضها أبطأ بشكل كبير.إذا كنت تقوم بتشغيل هذا النظام (مثلا ، ويندوز) الذي يحتوي I/O نموذج مختلفة بشكل ملحوظ عن C, يمكنك الحصول على أكثر من ذلك بكثير مع القليل من الرعاية.

المشكلة هي بسيطة إلى حد ما:الملف كنت تقرأ هو (يحتمل) أكبر من ذاكرة التخزين المؤقت المساحة المتوفرة لديك -- ولكنك لن تكسب أي شيء من التخزين المؤقت, لأنك لن نعيد قراءة أجزاء من الملف مرة أخرى (على الأقل إذا كنت تفعل الأشياء بشكل معقول).كما أريد أن أقول النظام لتجاوز أي التخزين المؤقت فقط نقل البيانات مباشرة من القرص إلى الذاكرة الخاصة بك حيث يمكنك العملية.في نظام يونكس مثل هذا ربما open() و read() (و لن تكسب أنت الكثير).على ويندوز ، CreateFile و ReadFile, تمرير FILE_FLAG_NO_BUFFERING العلم CreateFile -- و ربما تقريبا ضعف سرعة الخاص بك إذا كنت تفعل ذلك الحق.

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

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

طالما أنت متأكد من أنها سوف تستخدم إلا على متعدد المعالج (multi-core) آلة الحقيقي باستخدام الخيوط الدقيقة.إذا كان هناك فرصة هذا قد يكون من أي وقت مضى القيام به على جهاز واحد الجهاز الأساسية ستكون إلى حد ما أفضل حالا باستخدام خيط واحد مع/الإخراج المتراكب بدلا من ذلك.

كما أن آخرين قد أشارت إلى عنق الزجاجة سيكون القرص I/O.ولذلك نقترح عليك استخدام تتداخل I/O.هذا في الأساس يعكس منطق البرنامج.بدلا من التعليمات البرمجية الخاصة بك tyring لتحديد متى تفعل I/O, كنت أقول ببساطة نظام التشغيل إلى استدعاء التعليمات البرمجية الخاصة بك كلما انتهى قليلا من I/O.إذا كنت تستخدم I/O الانتهاء الموانئ, يمكنك حتى معرفة نظام التشغيل إلى استخدام مؤشرات ترابط متعددة لمعالجة الملف قطع.

ج على أساس حل ؟

أعتقد بيرل ولد لهذا الغرض المحدد.

تيار واحد فقط المؤشر.إذا كنت الوصول إلى تيار مع أكثر من موضوع واحد في كل مرة ، فلن تأكد من قراءة حيث تريد.قراءة من موضع المؤشر.

ما أود القيام به هو أن يكون مؤشر واحد فقط (ربما واحد الرئيسي) أن يقرأ تيار وإرسال القراءة بايت إلى المواضيع الأخرى.

على سبيل المثال:

  • موضوع #أنا جاهز و نسأل الترابط الرئيسي أن تعطيه ،
  • الرئيسية قراءة الموضوع التالي 1Mb و توفر لهم الخيط 1,
  • موضوع #قرأت 1Mb و عدد الكلمات كما تريد ،
  • الموضوع #i انتهاء عملها ونسأل مرة أخرى القادم 1Mb.

بهذه الطريقة يمكنك فصل تيار القراءة إلى تيار التحليل.

ما تبحث عنه هو RegEx.هذا ستاكوفيرفلوو الخيط على c++ regex محركات تساعدك:

C++:ما regex المكتبة التي يجب استخدامها ؟

أولا ، أنا متأكد من أن C/C++ ليست أفضل طريقة للتعامل مع هذا.من الأحسن أن استخدام بعض الخريطة/تخفيض على التوازي أيضا.

ولكن على افتراض القيود الخاصة بك, وهنا ما أود القيام به.

1) تقسيم ملف نصي إلى قطع أصغر.ليس عليك أن تفعل هذا من خلال أول حرف من الكلمة.فقط في, قول, 5000 كلمة قطع.في شبة الكود ، كنت تفعل شيئا من هذا القبيل:

index = 0

numwords = 0

mysplitfile = openfile(index-split.txt)

بينما (bigfile >> كلمة)

mysplitfile << word

numwords ++

if (numwords > 5000)

    mysplitfile.close()

    index++

    mysplitfile = openfile(index-split.txt)

2) استخدام مشترك خريطة البيانات هيكل pthreads تفرخ مواضيع جديدة لقراءة كل من subfiles.مرة أخرى, شبة الكود:

maplock = create_pthread_lock()

sharedmap = std::خريطة()

كل index-split.txt ملف:

spawn-new-thread(myfunction, filename, sharedmap, lock)

dump_map(sharedmap)

الفراغ myfunction(اسم الملف ، sharedmap) {

localmap = std::map<string, size_t>();

file = openfile(filename)

while (file >> word)

    if !localmap.contains(word)
         localmap[word] = 0

    localmap[word]++

acquire(lock)
for key,value in localmap
    if !sharedmap.contains(key)
         sharedmap[key] = 0

    sharedmap[key] += value
release(lock)

}

آسف على بناء الجملة.لقد تم كتابة الكثير من الثعبان في الآونة الأخيرة.

لا ج قليلا القبيح ، ولكن الأمر استغرق فقط 2 دقائق على الانفجار من:

perl -lane '$h{$_}++ for @F; END{for $w (sort {$h{$b}<=>$h{$a} || $a cmp $b} keys %h) {print "$h{$w}\t$w"}}' file > freq

حلقة أكثر من كل سطر -n
تقسيم كل سطر في @F الكلمات -a
كل $_ كلمة الزيادات تجزئة %h
مرة واحدة END من file تم التوصل إليه ،
sort تجزئة عن طريق التردد $h{$b}<=>$h{$a}
إذا اثنين من الترددات متطابقة ، فرز أبجديا $a cmp $b
طباعة تردد $h{$w} و كلمة $w
توجيه النتائج إلى ملف التكرار'

ركضت هذا الرمز على 3.3 GB ملف نصي مع 580,000,000 الكلمات.
بيرل 5.22 الانتهاء في 173 ثانية.

رأيي الملف بالفعل علامات الترقيم جردت و تحويل الأحرف الكبيرة إلى صغيرة ، باستخدام هذا قليلا من التعليمات البرمجية:
perl -pe "s/[^a-zA-Z \t\n']/ /g; tr/A-Z/a-z/" file_raw > file
(وقت التشغيل من 144 ثانية)


كلمة عد مخطوط بالتناوب تكون مكتوبة في awk:
awk '{for (i=1; i<=NF; i++){h[$i]++}} END{for (w in h){printf("%s\t%s\n", h[w], w)}}' file | sort -rn > freq

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