<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          C++核心準(zhǔn)則Per.7:設(shè)計要為優(yōu)化做準(zhǔn)備

          9922ad59893603876c97a4726197fef5.webp

          Per.7: Design to enable optimization

          Per.7:設(shè)計要為優(yōu)化做準(zhǔn)備


          Reason(原因)

          Because we often need to optimize the initial design. Because a design that ignores the possibility of later improvement is hard to change.

          因為我們經(jīng)常需要優(yōu)化最初的設(shè)計。忽略將來的發(fā)展可能性的設(shè)計很難變更。


          Example(示例)

          From the C (and C++) standard:

          來自C(和C++)標(biāo)準(zhǔn):

          void qsort (void* base, size_t num, size_t size, int (*compar)(const void*, const void*));

          When did you even want to sort memory? Really, we sort sequences of elements, typically stored in containers. A call to?qsort?throws away much useful information (e.g., the element type), forces the user to repeat information already known (e.g., the element size), and forces the user to write extra code (e.g., a function to compare?doubles). This implies added work for the programmer, is error-prone, and deprives the compiler of information needed for optimization.

          你什么時候有過內(nèi)存排序的需求?事實上,我們對通常保存在容器中的元素排序??焖倥判蛘{(diào)用丟掉了特別有用信息(例如元素類型),要求用戶重復(fù)提供已知的信息(例如元素大小),要求用戶書寫額外的代碼(例如雙精度數(shù)比較函數(shù))。這個實現(xiàn)會增加程序員的工作,易錯,使編譯器無法獲得可用于優(yōu)化的信息。

          double data[100];
          // ... fill a ...

          // 100 chunks of memory of sizeof(double) starting at
          // address data using the order defined by compare_doubles
          qsort(data, 100, sizeof(double), compare_doubles);

          From the point of view of interface design is that?qsort?throws away useful information.

          從接口設(shè)計的觀點來看,qsort丟掉了有用的信息。

          We can do better (in C++98)

          我們可以做得好一些(C++98)

          template
          void sort(Iter b, Iter e); // sort [b:e)

          sort(data, data + 100);

          Here, we use the compiler's knowledge about the size of the array, the type of elements, and how to compare?doubles.

          這里我們使用的編譯器已經(jīng)知道了數(shù)組大小信息,元素的類型,比較雙精度數(shù)的方法等。

          With C++11 plus?concepts, we can do better still

          使用C++11加概念,我們可以做得更好

          // Sortable specifies that c must be a
          // random-access sequence of elements comparable with <
          void sort(Sortable& c);

          sort(c);

          The key is to pass sufficient information for a good implementation to be chosen. In this, the?sort?interfaces shown here still have a weakness: They implicitly rely on the element type having less-than (<) defined. To complete the interface, we need a second version that accepts a comparison criteria:

          重要的是為選擇的良好實現(xiàn)傳遞足夠的信息。這段代碼中,sort結(jié)構(gòu)仍然有弱點:它隱含要求元素類型定義了小于(<)運算符。

          // compare elements of c using p
          void sort(Sortable& c, Predicate> p);

          The standard-library specification of?sort?offers those two versions, but the semantics is expressed in English rather than code using concepts.

          標(biāo)準(zhǔn)庫中定義的sort提供了上面的兩個版本,但是語義通過英語表達,而不是使用了concept的代碼。


          Note(注意)

          Premature optimization is said to be?the root of all evil, but that's not a reason to despise performance. It is never premature to consider what makes a design amenable to improvement, and improved performance is a commonly desired improvement. Aim to build a set of habits that by default results in efficient, maintainable, and optimizable code. In particular, when you write a function that is not a one-off implementation detail, consider

          過早的優(yōu)化被認(rèn)為是萬惡之源,但是這不應(yīng)該成為輕視性能的理由??紤]一個設(shè)計如何適應(yīng)變化永遠(yuǎn)不嫌早,改善性能也是最普通的提高。努力建立一套可以自然產(chǎn)生有效,可維護,可優(yōu)化代碼的習(xí)慣。通常情況下,當(dāng)你編寫一個可以復(fù)用的函數(shù)時:

          • Information passing: Prefer clean?interfaces?carrying sufficient information for later improvement of implementation. Note that information flows into and out of an implementation through the interfaces we provide.

          • 信息傳遞:提供可以為進一步開發(fā)提供足夠信息的清晰的接口。注意透過我們提供的接口進出的信息流。

          • Compact data: By default,?use compact data, such as?std::vector?and?access it in a systematic fashion. If you think you need a linked structure, try to craft the interface so that this structure isn't seen by users.

          • 緊湊數(shù)據(jù):默認(rèn)情況下,使用緊湊數(shù)據(jù),例如std::vector并使用系統(tǒng)化的方式進行訪問。如果你覺得你需要鏈?zhǔn)浇Y(jié)構(gòu),努力調(diào)整接口以保證該結(jié)構(gòu)對用戶不可見。

          • Function argument passing and return: Distinguish between mutable and non-mutable data. Don't impose a resource management burden on your users. Don't impose spurious run-time indirections on your users. Use?conventional ways?of passing information through an interface; unconventional and/or "optimized" ways of passing data can seriously complicate later reimplementation.

          • 函數(shù)參數(shù)傳遞和返回:區(qū)別可修改和不能修改的數(shù)據(jù)。不要將資源管理責(zé)任強加給用戶。不要將虛假的運行時間接處理強加給用戶。使用慣用方式通過接口傳遞信息;以非慣用的,“優(yōu)化過的”方式傳遞數(shù)據(jù)會為以后的重新實現(xiàn)造成嚴(yán)重的困難。

          • Abstraction: Don't overgeneralize; a design that tries to cater for every possible use (and misuse) and defers every design decision for later (using compile-time or run-time indirections) is usually a complicated, bloated, hard-to-understand mess. Generalize from concrete examples, preserving performance as we generalize. Do not generalize based on mere speculation about future needs. The ideal is zero-overhead generalization.

          • 抽象:不要過度泛化;試圖讓設(shè)計適用于(包含錯誤用法)所有可能用法,或者(使用編譯時指令或執(zhí)行時指令)為將來(的優(yōu)化)推遲所有的設(shè)計判斷通常都會導(dǎo)致復(fù)雜,臃腫的,難以理解的混亂結(jié)果。從具體的示例進行泛化,泛化的同時維持性能。不要僅僅基于對將來需求的推測就進行泛化。理想的狀態(tài)是0開銷泛化。

          • Libraries: Use libraries with good interfaces. If no library is available build one yourself and imitate the interface style from a good library. The?standard library?is a good first place to look for inspiration.

          • 庫:使用具有良好接口的庫。如果沒有可用的庫,可以自己構(gòu)建一個并模仿優(yōu)秀庫的接口。標(biāo)準(zhǔn)庫可以作為尋找靈感的好起點。

          • Isolation: Isolate your code from messy and/or old-style code by providing an interface of your choosing to it. This is sometimes called "providing a wrapper" for the useful/necessary but messy code. Don't let bad designs "bleed into" your code.

          • 隔離:通過選擇一個接口將你的代碼和混亂代碼或舊風(fēng)格代碼進行隔離。這種方式有時被叫做為有用且必要的混亂代碼“提供一個封裝”。不要讓不好的設(shè)計流入你的代碼中。


          Example(示例)

          Consider(考慮):

          template
          bool binary_search(ForwardIterator first, ForwardIterator last, const T& val);

          binary_search(begin(c), end(c), 7)?will tell you whether?7?is in?c?or not. However, it will not tell you where that?7?is or whether there are more than one?7.

          binary_search(begin(c), end(c), 7)會告訴你7是否包含在c中。然而它不會告訴你7在哪里,也不會告訴你是否存在更多的7。

          Sometimes, just passing the minimal amount of information back (here,?true?or?false) is sufficient, but a good interface passes needed information back to the caller. Therefore, the standard library also offers

          有時,只返回最小限度的信息(這里是true或false)就足夠了,但是好的接口會向調(diào)用者提供需要的信息。因此,標(biāo)準(zhǔn)庫也提供了

          template
          ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& val);

          lower_bound?returns an iterator to the first match if any, otherwise to the first element greater than?val, or?last?if no such element is found.

          如果存在,lower_bound返回指向第一個匹配結(jié)果的迭代器,否則返回第一個大于val的元素,如果不存在匹配元素返回最后一個元素。

          However,?lower_bound?still doesn't return enough information for all uses, so the standard library also offers

          然而,lower_bound依然沒有返回可以滿足所有使用者需求的足夠的信息。因此標(biāo)準(zhǔn)庫也提供了

          template
          pair
          equal_range(ForwardIterator first, ForwardIterator last, const T& val);

          equal_range?returns a?pair?of iterators specifying the first and one beyond last match.

          equal_range返回了定義第一個匹配元素和最后一個匹配元素的下一個位置的迭代器對。

          auto r = equal_range(begin(c), end(c), 7);
          for (auto p = r.first; p != r.second; ++p)
          cout << *p << '\n';

          Obviously, these three interfaces are implemented by the same basic code. They are simply three ways of presenting the basic binary search algorithm to users, ranging from the simplest ("make simple things simple!") to returning complete, but not always needed, information ("don't hide useful information"). Naturally, crafting such a set of interfaces requires experience and domain knowledge.

          顯然,這三個接口是通過相同的基礎(chǔ)代碼實現(xiàn)的。這只是存在3種向使用者提供基本二進制檢索算法的方式的情況,范圍從最簡單的(讓簡單的事情保持簡單)到不會經(jīng)常用到的返回全部信息(不要隱藏有用信息)。很顯然,提供這樣的接口集合需要經(jīng)驗和領(lǐng)域知識。


          Note(注意)

          Do not simply craft the interface to match the first implementation and the first use case you think of. Once your first initial implementation is complete, review it; once you deploy it, mistakes will be hard to remedy.

          不要簡單地讓接口和第一次實現(xiàn)方式或你想象的第一次使用場景匹配。當(dāng)?shù)谝淮瓮瓿勺畛醯膶崿F(xiàn)時,重新審視一下;一旦發(fā)布,失誤很難挽回。


          Note(注意)

          A need for efficiency does not imply a need for?low-level code. High-level code does not imply slow or bloated.

          效率方面的需求不一定意味著低層次代碼。高層次代碼也不一定意味著低速和臃腫。


          Note(注意)

          Things have costs. Don't be paranoid about costs (modern computers really are very fast), but have a rough idea of the order of magnitude of cost of what you use. For example, have a rough idea of the cost of a memory access, a function call, a string comparison, a system call, a disk access, and a message through a network.

          凡事都需要成本。不要偏執(zhí)于成本(現(xiàn)代的計算機真的非??欤菍τ谡谑褂玫募夹g(shù)(或方法)的代價的順序,應(yīng)該有足夠的認(rèn)識。例如,對內(nèi)存訪問,函數(shù)調(diào)用,字符串比較,系統(tǒng)調(diào)用,磁盤訪問,網(wǎng)絡(luò)上的信息傳遞等的代價有足夠的理解。


          Note(注意)

          If you can only think of one implementation, you probably don't have something for which you can devise a stable interface. Maybe, it is just an implementation detail - not every piece of code needs a stable interface - but pause and consider. One question that can be useful is "what interface would be needed if this operation should be implemented using multiple threads? be vectorized?"

          如果只能想到一種實現(xiàn)方式,你可能對如何設(shè)計穩(wěn)定的接口沒有什么想法。也許,它只是一個實現(xiàn)細(xì)節(jié)-不是所有的代碼片段都需要穩(wěn)定的接口-但是停下來想一想。一個有用的問題是:如果你的操作用多線程實現(xiàn),需要什么樣的接口?需要向量化么?


          Note(注意)

          This rule does not contradict the?Don't optimize prematurely?rule. It complements it encouraging developers enable later - appropriate and non-premature - optimization, if and where needed.

          本規(guī)則和【Per.2 不要過早優(yōu)化】并不矛盾。作為【Per.2 不要過早優(yōu)化】的補充,本規(guī)則鼓勵程序員為將來的優(yōu)化做準(zhǔn)備-適當(dāng)而不是過早的優(yōu)化,如果需要的話。


          Enforcement(實施建議)

          Tricky. Maybe looking for?void*?function arguments will find examples of interfaces that hinder later optimization.

          不容易。也許尋找void* 函數(shù)參數(shù)可以發(fā)現(xiàn)將來接口優(yōu)化的例子。


          原文鏈接

          https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#per7-design-to-enable-optimization




          覺得本文有幫助?請分享給更多人。

          關(guān)注微信公眾號【面向?qū)ο笏伎肌枯p松學(xué)習(xí)每一天!

          面向?qū)ο箝_發(fā),面向?qū)ο笏伎迹?/span>


          瀏覽 68
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本不卡视频在线 | 欧美成人综合 | 噜噜噜成人精品视频夜色久 | 一区二区三区中文字幕 | a在线免费观看 |