diff options
Diffstat (limited to 'system/doc/efficiency_guide/commoncaveats.xml')
-rw-r--r-- | system/doc/efficiency_guide/commoncaveats.xml | 135 |
1 files changed, 65 insertions, 70 deletions
diff --git a/system/doc/efficiency_guide/commoncaveats.xml b/system/doc/efficiency_guide/commoncaveats.xml index 551b0a03e6..71991d342f 100644 --- a/system/doc/efficiency_guide/commoncaveats.xml +++ b/system/doc/efficiency_guide/commoncaveats.xml @@ -18,7 +18,6 @@ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. - </legalnotice> <title>Common Caveats</title> @@ -29,49 +28,50 @@ <file>commoncaveats.xml</file> </header> - <p>Here we list a few modules and BIFs to watch out for, and not only + <p>This section lists a few modules and BIFs to watch out for, not only from a performance point of view.</p> <section> - <title>The timer module</title> + <title>Timer Module</title> <p>Creating timers using <seealso marker="erts:erlang#erlang:send_after/3">erlang:send_after/3</seealso> - and <seealso marker="erts:erlang#erlang:start_timer/3">erlang:start_timer/3</seealso> + and + <seealso marker="erts:erlang#erlang:start_timer/3">erlang:start_timer/3</seealso> +, is much more efficient than using the timers provided by the - <seealso marker="stdlib:timer">timer</seealso> module. The - <c>timer</c> module uses a separate process to manage the timers, - and that process can easily become overloaded if many processes + <seealso marker="stdlib:timer">timer</seealso> module in STDLIB. + The <c>timer</c> module uses a separate process to manage the timers. + That process can easily become overloaded if many processes create and cancel timers frequently (especially when using the SMP emulator).</p> - <p>The functions in the <c>timer</c> module that do not manage timers (such as - <c>timer:tc/3</c> or <c>timer:sleep/1</c>), do not call the timer-server process - and are therefore harmless.</p> + <p>The functions in the <c>timer</c> module that do not manage timers + (such as <c>timer:tc/3</c> or <c>timer:sleep/1</c>), do not call the + timer-server process and are therefore harmless.</p> </section> <section> <title>list_to_atom/1</title> - <p>Atoms are not garbage-collected. Once an atom is created, it will never - be removed. The emulator will terminate if the limit for the number - of atoms (1048576 by default) is reached.</p> + <p>Atoms are not garbage-collected. Once an atom is created, it is never + removed. The emulator terminates if the limit for the number + of atoms (1,048,576 by default) is reached.</p> - <p>Therefore, converting arbitrary input strings to atoms could be - dangerous in a system that will run continuously. - If only certain well-defined atoms are allowed as input, you can use + <p>Therefore, converting arbitrary input strings to atoms can be + dangerous in a system that runs continuously. + If only certain well-defined atoms are allowed as input, <seealso marker="erts:erlang#list_to_existing_atom/1">list_to_existing_atom/1</seealso> + can be used to to guard against a denial-of-service attack. (All atoms that are allowed - must have been created earlier, for instance by simply using all of them + must have been created earlier, for example, by simply using all of them in a module and loading that module.)</p> <p>Using <c>list_to_atom/1</c> to construct an atom that is passed to - <c>apply/3</c> like this</p> - + <c>apply/3</c> as follows, is quite expensive and not recommended + in time-critical code:</p> <code type="erl"> -apply(list_to_atom("some_prefix"++Var), foo, Args)</code> - - <p>is quite expensive and is not recommended in time-critical code.</p> +apply(list_to_atom("some_prefix"++Var), foo, Args)</code> </section> <section> @@ -81,25 +81,25 @@ apply(list_to_atom("some_prefix"++Var), foo, Args)</code> length of the list, as opposed to <c>tuple_size/1</c>, <c>byte_size/1</c>, and <c>bit_size/1</c>, which all execute in constant time.</p> - <p>Normally you don't have to worry about the speed of <c>length/1</c>, - because it is efficiently implemented in C. In time critical-code, though, - you might want to avoid it if the input list could potentially be very long.</p> + <p>Normally, there is no need to worry about the speed of <c>length/1</c>, + because it is efficiently implemented in C. In time-critical code, + you might want to avoid it if the input list could potentially be very + long.</p> <p>Some uses of <c>length/1</c> can be replaced by matching. - For instance, this code</p> - + For example, the following code:</p> <code type="erl"> foo(L) when length(L) >= 3 -> ...</code> - <p>can be rewritten to</p> + <p>can be rewritten to:</p> <code type="erl"> foo([_,_,_|_]=L) -> ...</code> - <p>(One slight difference is that <c>length(L)</c> will fail if the <c>L</c> - is an improper list, while the pattern in the second code fragment will - accept an improper list.)</p> + <p>One slight difference is that <c>length(L)</c> fails if <c>L</c> + is an improper list, while the pattern in the second code fragment + accepts an improper list.</p> </section> <section> @@ -107,50 +107,49 @@ foo([_,_,_|_]=L) -> <p><seealso marker="erts:erlang#setelement/3">setelement/3</seealso> copies the tuple it modifies. Therefore, updating a tuple in a loop - using <c>setelement/3</c> will create a new copy of the tuple every time.</p> + using <c>setelement/3</c> creates a new copy of the tuple every time.</p> <p>There is one exception to the rule that the tuple is copied. If the compiler clearly can see that destructively updating the tuple would - give exactly the same result as if the tuple was copied, the call to - <c>setelement/3</c> will be replaced with a special destructive setelement - instruction. In the following code sequence</p> - + give the same result as if the tuple was copied, the call to + <c>setelement/3</c> is replaced with a special destructive <c>setelement</c> + instruction. In the following code sequence, the first <c>setelement/3</c> + call copies the tuple and modifies the ninth element:</p> <code type="erl"> multiple_setelement(T0) -> T1 = setelement(9, T0, bar), T2 = setelement(7, T1, foobar), setelement(5, T2, new_value).</code> - <p>the first <c>setelement/3</c> call will copy the tuple and modify the - ninth element. The two following <c>setelement/3</c> calls will modify + <p>The two following <c>setelement/3</c> calls modify the tuple in place.</p> - <p>For the optimization to be applied, <em>all</em> of the followings conditions + <p>For the optimization to be applied, <em>all</em> the followings conditions must be true:</p> <list type="bulleted"> <item>The indices must be integer literals, not variables or expressions.</item> <item>The indices must be given in descending order.</item> - <item>There must be no calls to other function in between the calls to + <item>There must be no calls to another function in between the calls to <c>setelement/3</c>.</item> <item>The tuple returned from one <c>setelement/3</c> call must only be used in the subsequent call to <c>setelement/3</c>.</item> </list> - <p>If it is not possible to structure the code as in the <c>multiple_setelement/1</c> + <p>If the code cannot be structured as in the <c>multiple_setelement/1</c> example, the best way to modify multiple elements in a large tuple is to - convert the tuple to a list, modify the list, and convert the list back to + convert the tuple to a list, modify the list, and convert it back to a tuple.</p> </section> <section> <title>size/1</title> - <p><c>size/1</c> returns the size for both tuples and binary.</p> + <p><c>size/1</c> returns the size for both tuples and binaries.</p> - <p>Using the new BIFs <c>tuple_size/1</c> and <c>byte_size/1</c> introduced - in R12B gives the compiler and run-time system more opportunities for - optimization. A further advantage is that the new BIFs could help Dialyzer + <p>Using the new BIFs <c>tuple_size/1</c> and <c>byte_size/1</c>, introduced + in R12B, gives the compiler and the runtime system more opportunities for + optimization. Another advantage is that the new BIFs can help Dialyzer to find more bugs in your program.</p> </section> @@ -159,22 +158,21 @@ multiple_setelement(T0) -> <p>It is usually more efficient to split a binary using matching instead of calling the <c>split_binary/2</c> function. Furthermore, mixing bit syntax matching and <c>split_binary/2</c> - may prevent some optimizations of bit syntax matching.</p> + can prevent some optimizations of bit syntax matching.</p> <p><em>DO</em></p> <code type="none"><![CDATA[ <<Bin1:Num/binary,Bin2/binary>> = Bin,]]></code> <p><em>DO NOT</em></p> <code type="none"> - {Bin1,Bin2} = split_binary(Bin, Num) - </code> + {Bin1,Bin2} = split_binary(Bin, Num)</code> </section> <section> - <title>The '--' operator</title> - <p>Note that the '<c>--</c>' operator has a complexity - proportional to the product of the length of its operands, - meaning that it will be very slow if both of its operands + <title>Operator "--"</title> + <p>The "<c>--</c>" operator has a complexity + proportional to the product of the length of its operands. + This means that the operator is very slow if both of its operands are long lists:</p> <p><em>DO NOT</em></p> @@ -182,42 +180,39 @@ multiple_setelement(T0) -> HugeList1 -- HugeList2]]></code> <p>Instead use the <seealso marker="stdlib:ordsets">ordsets</seealso> - module:</p> + module in STDLIB:</p> <p><em>DO</em></p> <code type="none"> HugeSet1 = ordsets:from_list(HugeList1), HugeSet2 = ordsets:from_list(HugeList2), - ordsets:subtract(HugeSet1, HugeSet2) - </code> + ordsets:subtract(HugeSet1, HugeSet2)</code> - <p>Obviously, that code will not work if the original order + <p>Obviously, that code does not work if the original order of the list is important. If the order of the list must be - preserved, do like this:</p> + preserved, do as follows:</p> <p><em>DO</em></p> <code type="none"><![CDATA[ Set = gb_sets:from_list(HugeList2), [E || E <- HugeList1, not gb_sets:is_element(E, Set)]]]></code> - <p>Subtle note 1: This code behaves differently from '<c>--</c>' - if the lists contain duplicate elements. (One occurrence - of an element in HugeList2 will remove <em>all</em> + <note><p>This code behaves differently from "<c>--</c>" + if the lists contain duplicate elements (one occurrence + of an element in HugeList2 removes <em>all</em> occurrences in HugeList1.)</p> + <p>Also, this code compares lists elements using the + "<c>==</c>" operator, while "<c>--</c>" uses the "<c>=:=</c>" operator. + If that difference is important, <c>sets</c> can be used instead of + <c>gb_sets</c>, but <c>sets:from_list/1</c> is much + slower than <c>gb_sets:from_list/1</c> for long lists.</p></note> - <p>Subtle note 2: This code compares lists elements using the - '<c>==</c>' operator, while '<c>--</c>' uses the '<c>=:=</c>'. If - that difference is important, <c>sets</c> can be used instead of - <c>gb_sets</c>, but note that <c>sets:from_list/1</c> is much - slower than <c>gb_sets:from_list/1</c> for long lists.</p> - - <p>Using the '<c>--</c>' operator to delete an element + <p>Using the "<c>--</c>" operator to delete an element from a list is not a performance problem:</p> <p><em>OK</em></p> <code type="none"> - HugeList1 -- [Element] - </code> + HugeList1 -- [Element]</code> </section> |