Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:
firstly array max is 40 - 41 KB which is pushed beyond then
thanks in advance
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Best way to allocate some memory first
by Fletch (Bishop) on Dec 02, 2021 at 22:52 UTC | |
You could do something like assigning to the last element ($array[39_999] = undef;), but if you're so worried about efficiency that handling 40k items is an issue perhaps perl isn't the best implementation choice. If you gave an Short, Self-Contained, Correct Example that might help with more specific suggestions.
The cake is a lie. | [reply] [d/l] |
by LanX (Saint) on Dec 02, 2021 at 23:04 UTC | |
interesting ... Devel::Peek shows different results for our two approaches... $#array=39_999 creates magic values... <Reveal this spoiler or all in this thread>
Cheers Rolf | [reply] [d/l] [select] |
by Fletch (Bishop) on Dec 03, 2021 at 11:48 UTC | |
I found a test script from 20 years ago here Re: array pre-allocation trick (top of thread array pre-allocation trick) and tweaked it to add a version explicitly assigning to the last item (with "last" in the name). Machine is of course faster so the rate's much different, but the numbers are maybe similar.
The cake is a lie. | [reply] [d/l] |
by LanX (Saint) on Dec 03, 2021 at 18:38 UTC | |
Re: Best way to allocate some memory first
by BillKSmith (Monsignor) on Dec 03, 2021 at 02:16 UTC | |
Bill
| [reply] |
Re: Best way to allocate some memory first
by choroba (Cardinal) on Dec 02, 2021 at 23:11 UTC | |
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] |
Re: Best way to allocate some memory first
by davido (Cardinal) on Dec 03, 2021 at 16:15 UTC | |
Can you demonstrate code that is taking too long because the array hasn't been pre-allocated? Seeing that would help in making suggestions on how to mitigate the problem. Dave | [reply] |
by davido (Cardinal) on Dec 03, 2021 at 18:30 UTC | |
I actually think you would be hard pressed to even demonstrate an advantage in pre-allocating the array. Update: The short answer is even with five million elements, and growing the non-pre-allocated array one element at a time, pre-allocating is a little SLOWER. What follows is my testing methodology and findings. If I build up an array by pre-allocating, then adding elements one by one within the range of indexes that was preallocated, and then build up another array just by adding elements one by one, I can compare elapsed times. When I do, the non-preallocation method seems to win every time, presumably because there's one less statement to execute. Here's an example that attempts to isolate just the parts that involve preallocation and building up of the array's elements:
On my system the output is:
As you can see, without preallocation is actually faster. One might wonder why I didn't use push. The reason was that push was adding elements to the end of the preallocated array, skipping past the part that had been preallocated. So that raises one other reason not to preallocate (aside from it not actually being faster): It may trick you. It's interesting that the size of the non-preallocated array is larger in terms of memory consumption than the preallocated one. This is both interesting and can be explained by explaining why preallocation isn't significantly faster than building the array up incrementally. It would be grossly inefficient to grow memory for an array one element at a time. The reason is that as an array grows, if a new contiguous chunk needed to be allocated every time, the contents of the previous contiguous chunk would need to be copied over to the new one, for each new element. When Perl allocates space for arrays, it leaves the array space to grow to avoid this issue. I don't know the growth plan it uses, but let's say initially Perl leaves enough room for 50 elements. When those 50 are used, Perl allocates a chunk large enough for 100 elements and copies the array into that new chunk. When that is filled, it allocates enough space for 200, and so on. These numbers are totally made up, but the point is it almost always allocates enough space for the array to grow past its current size. In the case of pre-allocation, the array growth algorithm hasn't applied. You requested a million elements, the actual array size in memory will be a million elements. Not 1.2 million (allowing for growth without further allocations). So in terms of memory consumption, the pre-allocation method was a little more efficient. But in terms of speed, the growth algorithm is already good enough to make the time it takes to grow an array inconsequential when compared to the time it takes to interpret and execute the statement that preallocates the array. So the pre-allocation microoptimization, even for an array of five million elements, is useless if your goal is to improve speed. Perl's array growth algorithm is similar to a C++ std::vector container class. And has similar time complexity characteristics. For adding elements at the end, allowing the array to grow as needed, the operation is considered O(1) amortized time. If speed is an issue, profile your code with Devel::Profile and solve the hotspots. Array allocation isn't going to be one of them. I modified the code above to remove "extra" stuff and to put the guts into a main() subroutine so that I could profile that subroutine using Devel::NYTProf. When I profiled, I see that the loop over the pre-allocated array takes 601 milliseconds. And the loop over the non-preallocated takes 603 milliseconds. However, the preallocation step takes 6.69 milliseconds. So the preallocated array operation (allocating, then iterating) takes a total of 608ms, versus 603 for non-preallocated. Therefore, my assertion earlier, that the act of pre-allocating actually consumes more wallclock time interpreting and processing the line of code than just letting Perl allocate as needed.
You can do this too: See the documentation for Devel::NYTProf. Dave | [reply] [d/l] [select] |
Re: Best way to allocate some memory first
by LanX (Saint) on Dec 02, 2021 at 22:53 UTC | |
> firstly array max is 40 - 41 KB which is pushed beyond then I doubt you measured it right, but $#array=40000 will expand an empty @array to 40001 slots. (well actually even more). But I doubt it'll allocate space for the included scalars ...(?)
update40 KB doesn't qualify as "large" in my book.
Cheers Rolf | [reply] [d/l] [select] |
Re: Best way to allocate some memory first
by Marshall (Canon) on Dec 03, 2021 at 22:11 UTC | |
Some years ago I spent literally days benchmarking and working with pre-sizing hash structures. Perl starts off with 8 hash "buckets". Every time that the hash doubles in size, 8,16,32,64, buckets etc. Perl has to re-visit every item in the hash to find it's new "hash index" (that's an entry in the hash table which is a pointer to a linked list). My conclusion was that pre-sizing a hash table to hold say 100K hash keys didn't matter at all in the scheme of things. I don't remember all of the initial "bucket array" sizes that I experimented with. A major factor in my analysis was, that the time spent actually using the hash completely dwarfed the time spent creating it in the first place. I took out the pre-sizing because it made no significant application perceptible difference. Perl itself will call low level C functions to do its internal data structure management. These are "very fast" functions. Yes, I can write an ASM function that will beat C memcpy(), but so what? (memcpy()is good C code, it uses byte operations to align onto a memory boundary and then proceeds from there. The compiler, except at extreme optimization levels, cannot recognize that there is a specialized ASM instruction that is much faster at these block memory operations.) Again, so what? Anyway, I am very skeptical that "pre-sizing a 41K Perl array" will make any difference at all in terms of overall application performance.
Update: I don't think that this will achieve the intended purpose, because undef is a value. This will mess things up when trying to decide how many elements are in the array now. | [reply] |