استخدم sendfile () لنسخ الملف باستخدام سلاسل الرسائل أو طريقة نسخ ملف فعالة أخرى
-
21-12-2019 - |
سؤال
أحاول استخدام استدعاء نظام Linux sendfile()
لنسخ ملف باستخدام المواضيع.
أنا مهتم بتحسين هذه الأجزاء من الكود:
fseek(fin, size * (number) / MAX_THREADS, SEEK_SET);
fseek(fout, size * (number) / MAX_THREADS, SEEK_SET);
/* ... */
fwrite(buff, 1, len, fout);
شفرة:
void* FileOperate::FileCpThread::threadCp(void *param)
{
Info *ft = (Info *)param;
FILE *fin = fopen(ft->fromfile, "r+");
FILE *fout = fopen(ft->tofile, "w+");
int size = getFileSize(ft->fromfile);
int number = ft->num;
fseek(fin, size * (number) / MAX_THREADS, SEEK_SET);
fseek(fout, size * (number) / MAX_THREADS, SEEK_SET);
char buff[1024] = {'\0'};
int len = 0;
int total = 0;
while((len = fread(buff, 1, sizeof(buff), fin)) > 0)
{
fwrite(buff, 1, len, fout);
total += len;
if(total > size/MAX_THREADS)
{
break;
}
}
fclose(fin);
fclose(fout);
}
المحلول
نسخ الملفات ليس مرتبطًا بوحدة المعالجة المركزية (CPU)؛إذا كان من المحتمل أن تجد أن القيد موجود على مستوى kernel ولا شيء يمكنك القيام به على مستوى المستخدم من شأنه أن يوازيه.
مثل هذه "التحسينات" التي يتم إجراؤها على محركات الأقراص الميكانيكية ستكون في الواقع تحط من قدر الإنتاجية.أنت تضيع الوقت في البحث عن الملف بدلاً من قراءته وكتابته.
إذا كان الملف طويلاً ولا تتوقع أن تحتاج إلى البيانات المقروءة أو المكتوبة في أي وقت قريب، فقد يكون من المغري استخدام O_DIRECT
العلم على فتح.هذه فكرة سيئة، منذ O_DIRECT
API هو في الأساس مكسورة حسب التصميم.
بدلا من ذلك، يجب عليك استخدام posix_fadvise
على كل من الملفات المصدر والوجهة، مع علامتي POSIX_FADV_SEQUENTIAL وPOSIX_FADV_NOREUSE.بعد انتهاء مكالمة الكتابة (أو إرسال الملف)، يلزمك الإبلاغ عن عدم الحاجة إلى البيانات بعد الآن - قم بتمرير POSIX_FADV_DONTNEED.بهذه الطريقة، لن يتم استخدام ذاكرة التخزين المؤقت للصفحة إلا بالقدر المطلوب للحفاظ على تدفق البيانات، وسيتم إعادة تدوير الصفحات بمجرد استهلاك البيانات (كتابتها على القرص).
ال sendfile
لن يدفع بيانات الملف إلى مساحة المستخدم، لذلك فهو يخفف بعض الضغط من الذاكرة وذاكرة التخزين المؤقت للمعالج.يتعلق هذا بالتحسين المعقول الآخر الوحيد الذي يمكنك إجراؤه لنسخ الملفات غير الخاصة بالجهاز.
من المرغوب أيضًا اختيار حجم القطعة المعقول.نظرًا لأن محركات الأقراص الحديثة تدفع ما يزيد عن 100 ميجابايت/ثانية، فقد ترغب في دفع ميغابايت في المرة الواحدة، ويكون ذلك دائمًا مضاعفًا لحجم الصفحة البالغ 4096 بايت - وبالتالي (4096*256)
هو حجم قطعة بداية مناسب للتعامل معه في قطعة واحدة sendfile
أو read
/write
المكالمات.
قراءة الموازاة، كما تقترحها، تكون منطقية فقط على وحدات تخزين RAID 0، وفقط عندما تكون ملفات الإدخال والإخراج ممتدة على الأقراص الفعلية.يمكنك بعد ذلك الحصول على مؤشر ترابط واحد لكل أقل عدد من الأقراص الفعلية لوحدة تخزين المصدر والوجهة المتداخلة مع الملف.يعد ذلك ضروريًا فقط إذا كنت لا تستخدم إدخال/إخراج ملف غير متزامن.مع الإدخال/الإخراج غير المتزامن، لن تحتاج إلى أكثر من مؤشر ترابط واحد على أي حال، لا سيما إذا كانت أحجام القطع كبيرة (ميجابايت +) وكانت عقوبة زمن الوصول للخيط الواحد ضئيلة.
ليس هناك أي معنى لموازاة نسخة ملف واحد على محركات أقراص SSD، إلا إذا كنت تستخدم نظامًا غريبًا جدًا بالفعل.