Tại sao khó có thể cấp hiệu quả trong khi sử dụng thư viện?


10

Bất kỳ xử lý cơ sở dữ liệu nhỏ nào cũng có thể được xử lý dễ dàng bằng các tập lệnh Python / Perl / ..., sử dụng các thư viện và / hoặc thậm chí các tiện ích từ chính ngôn ngữ. Tuy nhiên, khi nói đến hiệu suất, mọi người có xu hướng tiếp cận với C / C ++ / ngôn ngữ cấp thấp. Khả năng điều chỉnh mã theo nhu cầu dường như là điều khiến các ngôn ngữ này trở nên hấp dẫn đối với BigData - có thể liên quan đến quản lý bộ nhớ, song song, truy cập đĩa hoặc thậm chí tối ưu hóa ở mức độ thấp (thông qua các cấu trúc lắp ráp ở cấp độ C / C ++).

Tất nhiên các lợi ích như vậy sẽ không đến nếu không có chi phí: viết mã, và đôi khi thậm chí phát minh lại bánh xe , có thể khá tốn kém / mệt mỏi. Mặc dù có rất nhiều thư viện có sẵn, mọi người có xu hướng tự viết mã bất cứ khi nào họ cần để cấp hiệu suất. Điều gì vô hiệu hóa các xác nhận hiệu suất từ ​​việc sử dụng các thư viện trong khi xử lý cơ sở dữ liệu lớn?

Ví dụ: hãy xem xét một sự ủy thác liên tục thu thập dữ liệu trang web và phân tích dữ liệu được thu thập. Đối với mỗi cửa sổ trượt, các thuật toán khai thác dữ liệu khác nhau được chạy dựa trên dữ liệu được trích xuất. Tại sao các nhà phát triển sẽ bỏ qua việc sử dụng các thư viện / khung có sẵn (có thể để thu thập dữ liệu, xử lý văn bản và khai thác dữ liệu)? Sử dụng công cụ đã được thực hiện sẽ không chỉ giảm bớt gánh nặng mã hóa toàn bộ quá trình, mà còn tiết kiệm rất nhiều thời gian.

Trong một lần chụp :

  • Điều gì làm cho việc tự viết mã là một sự đảm bảo về hiệu suất?
  • Tại sao rủi ro khi dựa vào khung / thư viện khi bạn phải đảm bảo hiệu suất cao?

1
Bạn có thể làm rõ câu hỏi chính xác? Có thể một số câu trả lời có thể bạn có trong tâm trí cũng có thể giúp đỡ.
Amir Ali Akbari

@AmirAliAkbari SeanOwen đã đăng một câu trả lời và tôi nhận thấy sự thiếu cụ thể trong câu hỏi của tôi. Tôi đã thêm một bình luận cho bài viết của mình. Xin vui lòng, đề nghị bất kỳ cải tiến trên bài đăng - nếu không, tôi dự định xóa nó, nếu không.
Rubens

Câu trả lời:


4

Sau khi thực hiện trò chơi viết lại nhiều lần (và vẫn đang thực hiện), phản ứng ngay lập tức của tôi là khả năng thích ứng .

Trong khi các khung và thư viện có một kho lớn các thói quen (có thể có thể đan xen) cho các tác vụ tiêu chuẩn, thuộc tính khung của chúng thường (luôn luôn?) Không cho phép các phím tắt. Trong thực tế, hầu hết các khung công tác có một số loại cơ sở hạ tầng cốt lõi xung quanh đó một lớp lõi của chức năng cơ bản được triển khai. Chức năng cụ thể hơn sử dụng lớp cơ bản và được đặt trong lớp thứ hai xung quanh lõi.

Bây giờ bằng các phím tắt, tôi có nghĩa là đi thẳng từ một thói quen lớp thứ hai sang một thói quen lớp thứ hai khác mà không sử dụng lõi. Ví dụ điển hình (từ tên miền của tôi) sẽ là dấu thời gian: Bạn có một nguồn dữ liệu được đánh dấu thời gian của một số loại. Cho đến nay, công việc chỉ đơn giản là đọc dữ liệu ra khỏi dây và chuyển nó vào lõi để mã khác của bạn có thể ăn vào nó.

Bây giờ ngành của bạn thay đổi định dạng dấu thời gian mặc định vì một lý do rất chính đáng (trong trường hợp của tôi họ đã chuyển từ thời gian unix sang thời gian GPS). Trừ khi khung của bạn là dành riêng cho ngành, rất khó có khả năng họ sẵn sàng thay đổi đại diện cốt lõi của thời gian, vì vậy cuối cùng bạn sẽ sử dụng một khung gần như làm những gì bạn muốn. Mỗi lần bạn truy cập dữ liệu của mình, trước tiên bạn phải chuyển đổi nó sang định dạng theo thời gian của ngành và mỗi lần bạn muốn sửa đổi, bạn phải chuyển đổi lại thành bất cứ điều gì cốt lõi thấy phù hợp. Không có cách nào bạn có thể bàn giao dữ liệu trực tiếp từ nguồn vào bồn mà không cần chuyển đổi kép.

Đây là nơi các khung làm thủ công của bạn sẽ tỏa sáng, đó chỉ là một thay đổi nhỏ và bạn quay lại mô hình hóa thế giới thực trong khi tất cả các khung (không dành riêng cho ngành công nghiệp) khác sẽ gặp bất lợi về hiệu suất.

Theo thời gian, sự khác biệt giữa thế giới thực và mô hình sẽ tăng lên. Với một khung off-the-shelf bạn muốn sớm phải đối mặt với những câu hỏi như: Làm thế nào tôi có thể biểu diễn thisthathoặc làm thế nào để làm cho thói quen Xchấp nhận / sản phẩm Y.

Cho đến nay điều này không phải là về C / C ++. Nhưng nếu vì một lý do nào đó, bạn không thể thay đổi khung, tức là bạn phải đưa ra chuyển đổi dữ liệu gấp đôi để đi từ đầu này sang đầu khác, thì bạn thường sử dụng thứ gì đó để giảm thiểu chi phí bổ sung. Trong trường hợp của tôi, bộ chuyển đổi TAI-> UTC hoặc UTC-> TAI tốt nhất là để nguyên C (hoặc một đồ họa). Không có sự tao nhã có thể, không có cấu trúc dữ liệu thông minh sâu sắc làm cho vấn đề trở nên tầm thường. Đó chỉ là một câu lệnh chuyển đổi nhàm chán, và tại sao không sử dụng một ngôn ngữ có trình biên dịch tốt để tối ưu hóa chính xác điều đó?


1
+1 Đó có thể là lỗi của tôi vì không rõ ràng trong bài viết của tôi, vì vậy những người khác đã không nhận được nó trước đây. Đây chắc chắn là loại câu trả lời tôi đang tìm kiếm. Cảm ơn.
Rubens

7

Tôi không nghĩ rằng mọi người đều đạt C / C ++ khi hiệu suất là một vấn đề.

Lợi thế để viết mã cấp thấp là sử dụng ít chu kỳ CPU hơn, hoặc đôi khi, ít bộ nhớ hơn. Nhưng tôi lưu ý rằng các ngôn ngữ cấp cao hơn có thể gọi các ngôn ngữ cấp thấp hơn và thực hiện để có được một số giá trị này. Ngôn ngữ Python và JVM có thể làm điều này.

Nhà khoa học dữ liệu sử dụng, ví dụ, scikit-learn trên máy tính để bàn của cô ấy đã gọi các thói quen bản địa được tối ưu hóa mạnh mẽ để thực hiện số. Không có điểm nào trong việc viết mã mới cho tốc độ.

Trong ngữ cảnh "dữ liệu lớn" phân tán, bạn thường bị tắc nghẽn khi di chuyển dữ liệu: truyền mạng và I / O. Mã riêng không giúp được gì. Điều giúp không phải là viết cùng một mã để chạy nhanh hơn, mà là viết mã thông minh hơn.

Các ngôn ngữ cấp cao hơn sẽ cho phép bạn triển khai các thuật toán phân tán tinh vi hơn trong một khoảng thời gian nhất định của nhà phát triển so với C / C ++. Ở quy mô, thuật toán thông minh hơn với chuyển động dữ liệu tốt hơn sẽ đánh bại mã gốc câm.

Điều này cũng thường đúng với thời gian của nhà phát triển và các lỗi, chi phí tải nhiều hơn phần cứng mới. Một năm của nhà phát triển cấp cao có thể được nạp đầy đủ $ 200K; trong một năm cũng cho thuê hàng trăm máy chủ có giá trị thời gian tính toán. Nó có thể không có ý nghĩa trong hầu hết các trường hợp để bận tâm tối ưu hóa hơn việc ném thêm phần cứng vào nó.

Tôi không hiểu theo dõi về "cấp" và "vô hiệu hóa" và "khẳng định"?


Xin lỗi vì sự hiểu lầm. Ý định của tôi là đưa ra các câu trả lời liên quan đến tầm quan trọng của việc kiểm soát ứng dụng và cách thức kiểm soát này được các thư viện nới lỏng . Tất nhiên bạn có thể giả định mọi thứ về chúng (mọi người thường không viết lại pthread), nhưng nếu dữ liệu thay đổi (tải, thông lượng, ...), bạn có thể cần truy cập nguồn lib để cấp hiệu suất. Và vâng, nó không nhất thiết phải là C / C ++ - mặc dù chúng thường là ngôn ngữ được chọn cho hpc. Tôi có thể xóa câu hỏi của mình không, hoặc bạn muốn thay đổi nó thành một cái gì đó cụ thể hơn? Tôi chấp nhận bất kỳ đề xuất để cải thiện nó.
Rubens

1
Không, đó là một câu hỏi hay, bạn có thể phản ánh ý kiến ​​của mình ở đây để chỉnh sửa câu hỏi nếu bạn thích.
Sean Owen

Xin vui lòng, kiểm tra nếu câu hỏi có ý nghĩa bây giờ. Tôi đã thêm một trường hợp nhỏ để làm cho nó đơn giản hơn. Trong trường hợp bạn muốn thêm một số xem xét trong câu hỏi, xin vui lòng, chỉnh sửa nó.
Rubens

4

Như tất cả những gì chúng ta biết, trong thế giới Kỹ thuật số có nhiều cách để thực hiện cùng một công việc / nhận được kết quả mong đợi ..

Và trách nhiệm / rủi ro xuất phát từ mã nằm trên vai nhà phát triển ..

Điều này là nhỏ nhưng tôi đoán một ví dụ rất hữu ích từ thế giới .NET ..

Vì vậy, nhiều nhà phát triển .NET sử dụng BinaryReader tích hợp - BinaryWriter trên tuần tự hóa dữ liệu của họ để thực hiện / kiểm soát quá trình ..

Đây là mã nguồn CSharp của FrameWork được xây dựng trong lớp BinaryWriter 'một trong những Phương thức ghi bị quá tải:

// Writes a boolean to this stream. A single byte is written to the stream
// with the value 0 representing false or the value 1 representing true.
// 
public virtual void Write(bool value) 
{
     //_buffer is a byte array which declared in ctor / init codes of the class
    _buffer = ((byte) (value? 1:0));

    //OutStream is the stream instance which BinaryWriter Writes the value(s) into it.
    OutStream.WriteByte(_buffer[0]);
}

Như bạn thấy, phương thức này có thể được viết mà không cần gán thêm cho biến _buffer:

public virtual void Write(bool value) 
{
    OutStream.WriteByte((byte) (value ? 1 : 0));
}

Nếu không chỉ định, chúng ta có thể đạt được vài mili giây .. Vài mili giây này có thể chấp nhận là "gần như không có gì" nhưng nếu có hàng ngàn chữ viết (nghĩa là trong một quy trình máy chủ) thì sao?

Giả sử rằng "vài" là 2 (mili giây) và nhiều trường hợp Hàng nghìn chỉ là 2.000 .. Điều này có nghĩa là 4 giây nữa thời gian xử lý..4 giây sau trở lại ..

Nếu chúng tôi tiếp tục chủ đề từ .NET và nếu bạn có thể kiểm tra mã nguồn của BCL - Thư viện lớp cơ sở .NET - từ MSDN, bạn có thể thấy rất nhiều hiệu suất bị mất từ ​​nhà phát triển quyết định ..

Bất kỳ điểm nào từ nguồn BCL Điều bình thường là bạn thấy nhà phát triển đã quyết định sử dụng các vòng lặp while () hoặc foreach () có thể thực hiện vòng lặp for () nhanh hơn trong mã của họ.

Lợi ích nhỏ này cho chúng ta tổng hiệu suất ..

Và nếu chúng ta quay lại Phương thức BinaryWriter.Write () ..

Trên thực tế, việc chỉ định thêm cho việc triển khai _buffer không phải là lỗi của nhà phát triển..Đây chính xác là quyết định "giữ an toàn"!

Giả sử rằng chúng tôi quyết định không sử dụng _buffer và quyết định thực hiện phương thức thứ hai..Nếu chúng tôi cố gắng gửi nhiều nghìn byte qua một dây (tức là tải lên / tải xuống dữ liệu BLOB hoặc CLOB) bằng phương thức thứ hai, nó có thể thất bại thường vì mất kết nối .. Vì chúng tôi cố gắng gửi tất cả dữ liệu mà không có bất kỳ kiểm tra và cơ chế kiểm soát nào. Khi mất kết nối, cả máy chủ và Máy khách không bao giờ biết dữ liệu đã gửi đã hoàn thành hay chưa.

Nếu nhà phát triển quyết định "giữ an toàn" thì thông thường, điều đó có nghĩa là chi phí hiệu suất phụ thuộc vào cơ chế "giữ an toàn".

Nhưng nếu nhà phát triển quyết định "gặp rủi ro, đạt được hiệu suất" thì đây cũng không phải là lỗi..Tuy nhiên có một số cuộc thảo luận về mã hóa "rủi ro".

Và như một lưu ý nhỏ: Các nhà phát triển thư viện thương mại luôn cố gắng giữ an toàn vì họ không thể biết mã của họ sẽ sử dụng ở đâu.


4

Xuất phát từ quan điểm lập trình viên, các khung công tác hiếm khi nhắm mục tiêu hiệu suất là ưu tiên cao nhất. Nếu thư viện của bạn sẽ được tận dụng rộng rãi, những thứ mà mọi người có thể đánh giá cao nhất là dễ sử dụng, linh hoạt và đáng tin cậy.

Hiệu suất thường có giá trị trong các thư viện cạnh tranh thứ cấp. "Thư viện X tốt hơn vì nó nhanh hơn." Thậm chí sau đó rất thường xuyên những thư viện đó sẽ đánh đổi giải pháp tối ưu nhất cho một giải pháp có thể được tận dụng rộng rãi.

Bằng cách sử dụng bất kỳ khuôn khổ nào, bạn vốn đang chấp nhận rủi ro rằng một giải pháp nhanh hơn tồn tại. Tôi có thể đi xa để nói rằng một giải pháp nhanh hơn hầu như luôn tồn tại.

Tự viết một cái gì đó không phải là một sự đảm bảo về hiệu suất, nhưng nếu bạn biết những gì bạn đang làm và có một bộ yêu cầu khá hạn chế thì nó có thể giúp ích.

Một ví dụ có thể là phân tích cú pháp JSON. Có hàng trăm thư viện ngoài kia cho nhiều ngôn ngữ sẽ biến JSON thành một đối tượng có thể tham khảo và ngược lại. Tôi biết một triển khai thực hiện tất cả trong các thanh ghi CPU. Nó nhanh hơn tất cả các trình phân tích cú pháp khác, nhưng nó cũng rất hạn chế và giới hạn đó sẽ thay đổi dựa trên CPU mà bạn đang làm việc.

Có phải nhiệm vụ xây dựng một trình phân tích cú pháp JSON cụ thể cho môi trường hiệu suất cao là một ý tưởng tốt? Tôi sẽ tận dụng một thư viện được tôn trọng 99 lần trong số 100. Trong trường hợp riêng biệt đó, một vài chu kỳ CPU bổ sung được nhân với một triệu lần lặp sẽ khiến thời gian phát triển trở nên đáng giá.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.