2012-05-12 25 views
16

Dường như có nhiều nhầm lẫn về mục đích của kích thước của hai đối số 'và' đếm 'trong fwrite(). Tôi cố gắng để tìm ra sẽ nhanh hơn -fwrite() - ảnh hưởng của kích thước và tính trên hiệu suất

fwrite(source, 1, 50000, destination); 

hoặc

fwrite(source, 50000, 1, destination); 

Đây là một quyết định quan trọng trong mã của tôi như là lệnh này sẽ được thực hiện hàng triệu lần.

Bây giờ, tôi chỉ có thể chuyển sang thử nghiệm và sử dụng kết quả có kết quả tốt hơn, nhưng vấn đề là mã dành cho nền tảng MANY.

Vì vậy,

  • Làm thế nào tôi có thể nhận được một câu trả lời dứt khoát mà là tốt hơn trên nền tảng?

  • Logic thực hiện của fwrite() có thay đổi từ nền tảng đến nền tảng không?

Tôi nhận ra có những câu hỏi tương tự (What is the rationale for fread/fwrite taking size and count as arguments?, Performance of fwrite and write size) nhưng tôi hiểu rằng đây là một câu hỏi khác nhau về cùng một vấn đề. Các câu trả lời trong các câu hỏi tương tự không đủ trong trường hợp này.

+0

Tôi vừa thực hiện một số thử nghiệm trên OS-X, viết mười tệp 100MB và không có sự khác biệt giữa thứ tự tham số hoặc khi viết (2) thay vì fwrite. Đối với các nền tảng khác, tôi không thể nói. –

Trả lời

13

Hiệu suất không được phụ thuộc vào một trong hai cách, bởi vì bất kỳ ai thực hiện fwrite sẽ nhân kích thước và đếm để xác định số lượng I/O cần làm.

này được minh chứng bằng thực hiện libc FreeBSD của fwrite.c, mà trong toàn bộ đọc (bao gồm chỉ thị elided):

/* 
* Write `count' objects (each size `size') from memory to the given file. 
* Return the number of whole objects written. 
*/ 
size_t 
fwrite(buf, size, count, fp) 
    const void * __restrict buf; 
    size_t size, count; 
    FILE * __restrict fp; 
{ 
    size_t n; 
    struct __suio uio; 
    struct __siov iov; 

    /* 
    * ANSI and SUSv2 require a return value of 0 if size or count are 0. 
    */ 
    if ((count == 0) || (size == 0)) 
     return (0); 

    /* 
    * Check for integer overflow. As an optimization, first check that 
    * at least one of {count, size} is at least 2^16, since if both 
    * values are less than that, their product can't possible overflow 
    * (size_t is always at least 32 bits on FreeBSD). 
    */ 
    if (((count | size) > 0xFFFF) && 
     (count > SIZE_MAX/size)) { 
     errno = EINVAL; 
     fp->_flags |= __SERR; 
     return (0); 
    } 

    n = count * size; 

    iov.iov_base = (void *)buf; 
    uio.uio_resid = iov.iov_len = n; 
    uio.uio_iov = &iov; 
    uio.uio_iovcnt = 1; 

    FLOCKFILE(fp); 
    ORIENT(fp, -1); 
    /* 
    * The usual case is success (__sfvwrite returns 0); 
    * skip the divide if this happens, since divides are 
    * generally slow and since this occurs whenever size==0. 
    */ 
    if (__sfvwrite(fp, &uio) != 0) 
     count = (n - uio.uio_resid)/size; 
    FUNLOCKFILE(fp); 
    return (count); 
} 
+1

Tôi chạy thử nghiệm trên một số nền tảng và xem mã nguồn cho fwrite cho một số nền tảng khác, không có sự khác biệt về hiệu suất trong bất kỳ nền tảng nào. Cảm ơn! –

12

Mục đích của hai đối số được rõ ràng hơn, nếu bạn xem xét ther giá trị trả về, là số đối tượng được ghi thành công/đọc đến/từ luồng:

fwrite(src, 1, 50000, dst); // will return 50000 
fwrite(src, 50000, 1, dst); // will return 1 

Tốc độ có thể được thực hiện phụ thuộc mặc dù, tôi không mong đợi bất kỳ cân nhắc nào e khác biệt.

+2

+1: Cụ thể, lần đầu tiên sẽ thất bại nếu nó chỉ nhận được 49999 byte (trả về 0); thứ hai sẽ trả lại 49999 nếu đó là số byte mà nó đọc. Vì vậy, nếu dữ liệu của bạn là cứng nhắc 50.000 byte, nó quan trọng không phải trong ít nhất mà bạn sử dụng. Nếu dữ liệu của bạn không cứng nhắc nhưng có thể ngắn hơn, thì bạn cần tùy chọn linh hoạt hơn. –

+0

Tôi sử dụng sai 'fread' thay vì' fwrite' nhưng nguyên tắc tương tự cũng áp dụng cho cả hai. –

+0

@ AlešKotnik Vui lòng chỉnh sửa câu trả lời của bạn. – Jens

2

Tôi muốn chỉ cho bạn đến my question, kết thúc để lộ sự khác biệt hiệu suất thú vị giữa việc gọi fwrite một lần và gọi fwrite nhiều lần để viết tệp "theo khối".

Vấn đề của tôi là có lỗi trong việc triển khai fwrite của Microsoft nên các tệp lớn hơn 4GB không thể được viết trong một cuộc gọi (nó bị treo tại số fwrite). Vì vậy, tôi đã phải làm việc xung quanh điều này bằng cách viết các tập tin trong khối, gọi fwrite trong một vòng lặp cho đến khi dữ liệu được viết hoàn toàn. Tôi thấy rằng phương pháp sau này luôn trả về nhanh hơn lệnh gọi đơn fwrite.

Tôi đang ở trong Windows 7 x64 với RAM 32 GB, giúp ghi nhớ bộ nhớ đệm khá tích cực.