Tôi có một tập lệnh Perl mà crunches rất nhiều dữ liệu. Có một loạt các biến chuỗi bắt đầu nhỏ nhưng phát triển thực sự lâu do việc sử dụng lặp lại của toán tử dấu chấm (concatentation). Sẽ phát triển chuỗi theo cách này dẫn đến tái phân bổ lặp đi lặp lại? Nếu có, có cách nào để phân bổ trước một chuỗi không?Làm thế nào tôi có thể phân bổ trước một chuỗi trong Perl?
Trả lời
Có, các chuỗi mở rộng mà bạn biết sẽ phát triển là một ý tưởng hay.
Bạn có thể sử dụng toán tử 'x' để thực hiện việc này. Ví dụ, để preallocate 1000 không gian:
$ s = "" x 1000:
Và sau đó sử dụng chất nền trên các lhs của bài tập. Uuuuugly. – chaos
Trong khi điều này sẽ tạo một chuỗi chứa 1000 dấu cách, khi tôi nói "$ s = 'foo'", tôi có nhận được chuỗi gồm 1000 ký tự chỉ với ba ký tự đầu tiên được sử dụng hay không. ném đi? (Tôi nghi ngờ sau, nhưng không thực sự biết làm thế nào perl sẽ xử lý nó.) –
Nếu bạn gán lại nó, nó sẽ vứt bỏ kết quả cũ (giả sử đi tham chiếu đến nó). Bạn sẽ cần phải thay thế chuỗi, như Dave đã nói, để sửa đổi chỉ một phần của nó. ++ array-then-join – Anonymous
chuỗi Perl là có thể thay đổi, vì vậy phụ thêm vào một chuỗi làm KHÔNG phải chịu một hình phạt chuỗi trùng lặp.
Bạn có thể thử tất cả những gì bạn muốn tìm một cách "nhanh hơn", nhưng điều này có mùi thực sự xấu về tối ưu hóa sớm.
Ví dụ, tôi đã đánh lừa một lớp trừu tượng hóa công việc khó khăn. Nó hoạt động hoàn hảo, nhưng nó, cho tất cả các thủ thuật ngốc nghếch của nó, thực sự chậm.
Dưới đây là kết quả:
Rate magic normal
magic 1.72/s -- -93%
normal 23.9/s 1289% --
Vâng, đúng vậy, Perl nhanh hơn những gì tôi nghĩ là một việc thực hiện đáng kính 1200%.
Lập hồ sơ cho mã của bạn và tìm ra vấn đề thực sự là gì, đừng thử tối ưu hóa nội dung thậm chí không phải là vấn đề đã biết.
#!/usr/bin/perl
use strict;
use warnings;
{
package MagicString;
use Moose;
has _buffer => (
isa => 'Str',
is => 'rw',
);
has _buffer_size => (
isa => 'Int',
is => 'rw',
default => 0,
);
has step_size => (
isa => 'Int',
is => 'rw',
default => 32768,
);
has _tail_pos => (
isa => 'Int',
is => 'rw',
default => 0,
);
sub BUILD {
my $self = shift;
$self->_buffer(chr(0) x $self->step_size);
}
sub value {
my $self = shift;
return substr($self->{buffer}, 0, $self->{_tail_pos});
}
sub append {
my $self = shift;
my $value = shift;
my $L = length($value);
if (($self->{_tail_pos} + $L) > $self->{_buffer_size }){
$self->{buffer} .= (chr(0) x $self->{step_size});
$self->{_buffer_size} += $self->{step_size};
}
substr($self->{buffer}, $self->{_tail_pos}, $L, $value);
$self->{_tail_pos} += $L;
}
__PACKAGE__->meta->make_immutable;
}
use Benchmark qw(:all :hireswallclock);
cmpthese(-10 , {
magic => sub{
my $x = MagicString->new();
for (1 .. 200001){
$x->append("hello");
}
my $y = $x->value();
},
normal =>sub{
my $x = '';
for (1 .. 200001){
$x .= 'hello';
}
my $y = $x;
}
});
#use Data::Dumper;
#print Dumper(length($x->value()));
Nói Perl không trùng lặp chuỗi chỉ là một nửa sự thật. Perl chỉ phân bổ thêm một vài ký tự cho một chuỗi, vì vậy Perl sẽ rất có khả năng phát triển bộ nhớ chứa chuỗi khi chắp thêm. Điều này có thể làm cho bộ nhớ được sao chép. Nhưng điều này xảy ra trong trình quản lý bộ nhớ của hệ thống của bạn rất nhanh. Hãy nhớ rằng, O (n) sẽ đánh bại O (logn) trong lớp toán, nhưng trong thế giới thực, thời gian liên tục của thuật toán là quan trọng. C nhanh. – Schwern
Thật vậy, O (1) không phải là rất tốt nếu O (1) là vài ngày cho một bước, trong khi O (n^2) có thể mất vài giây :) Mặc dù, có thể là một lợi thế nếu kích thước dữ liệu của bạn quá lớn rằng cách tiếp cận O (n^2) vượt quá vài tuần và tập dữ liệu kích thước đó là phổ biến. –
Có, Perl đang phát triển một chuỗi sẽ dẫn đến lặp lại reallocations. Perl phân bổ thêm một chút không gian cho các chuỗi, nhưng chỉ một vài byte. Bạn có thể thấy điều này bằng cách sử dụng Devel :: Peek. Sự phân bổ lại này rất nhanh và thường không thực sự sao chép bộ nhớ. Tin tưởng người quản lý bộ nhớ của bạn, đó là lý do tại sao bạn đang lập trình trong Perl và không C. Benchmark nó đầu tiên!
Bạn có thể preallocate mảng với $#array = $num_entries
và một băm với keys %hash = $num_keys
nhưng length $string = $strlen
không hoạt động. Đây là số clever trick I dug up on Perlmonks.
my $str = "";
vec($str, $length, 8)=0;
$str = "";
Hoặc nếu bạn muốn tham gia XS, bạn có thể gọi SvGROW()
.
đề xuất hỗn loạn 'để sử dụng một mảng và sau đó kết hợp tất cả lại với nhau sẽ sử dụng nhiều hơn gấp đôi bộ nhớ. Bộ nhớ cho mảng. Bộ nhớ cho mỗi vô hướng được phân bổ cho từng phần tử trong mảng. Bộ nhớ cho chuỗi được giữ trong mỗi phần tử vô hướng. Bộ nhớ cho bản sao khi tham gia. Nếu nó kết quả trong mã đơn giản hơn, hãy làm điều đó, nhưng đừng nghĩ rằng bạn đang lưu bất kỳ bộ nhớ nào.
tôi sẽ đi mảng/join cách:
push(@array, $crunched_bit)
Và sau đó $str = join('', @array)
, nếu không có gì hơn, để có quyền truy cập vào tất cả các yếu tố để gỡ lỗi tại một số thời gian sau đó.
Điều này sẽ sử dụng khá nhiều bộ nhớ bổ sung vì mọi phần tử mảng cần có SV mới. –
Tôi không biết cụ thể cách chuỗi Perl được triển khai nhưng dự đoán khá tốt là đó là constant amortized time. Điều này có nghĩa rằng ngay cả khi bạn tìm cách để phân bổ trước cơ hội chuỗi của bạn là thời gian kết hợp nó sẽ tiết kiệm cho tất cả người dùng của tập lệnh sẽ nhỏ hơn thời gian bạn đã yêu cầu this question trên Stack Overflow.
- 1. Trong Perl, làm thế nào tôi có thể gọi một phương thức có tên tôi có trong một chuỗi?
- 2. Làm thế nào tôi có thể đoán mã hóa của một chuỗi trong Perl?
- 3. Làm thế nào tôi có thể trích dẫn một chuỗi dài trong Perl?
- 4. Làm thế nào tôi có thể lặp lại một chuỗi N lần trong Perl?
- 5. Làm thế nào tôi có thể bọc một chuỗi trong Perl?
- 6. Làm thế nào tôi có thể trích xuất các chất nền từ một chuỗi trong Perl?
- 7. Trong Perl, làm cách nào tôi có thể biết chuỗi là một số?
- 8. Làm thế nào tôi có thể chuyển đổi một chuỗi 48 hex thành byte bằng Perl?
- 9. Làm thế nào tôi có thể tham gia một danh sách thành một chuỗi (báo trước)?
- 10. Làm thế nào tôi có thể tách một chuỗi theo dấu phân cách trong Qt?
- 11. Làm thế nào tôi có thể gọi một tên hàm được định nghĩa trong một chuỗi ký tự trong perl?
- 12. Làm thế nào tôi có thể nhận được chiều cao của một chuỗi cho trước?
- 13. Làm cách nào tôi có thể nội suy thủ công chuỗi thoát trong chuỗi Perl?
- 14. Làm thế nào tôi có thể vẽ đồ thị chuỗi thời gian với Perl?
- 15. Làm thế nào tôi có thể chia chuỗi bằng dấu phân tách thành một mảng?
- 16. Làm thế nào tôi có thể tạm thời dừng STDOUT trong một chương trình Perl?
- 17. Làm thế nào tôi có thể làm một mã hóa nhị phân của một chuỗi trong python?
- 18. Làm thế nào để phân tích một chuỗi thành một đối tượng DateTime trong Perl?
- 19. Trong Perl, làm thế nào tôi có thể lặp qua nhiều phần tử của một mảng?
- 20. Trong Perl, làm thế nào tôi có thể đảm bảo rằng một chuỗi tương ứng với một ngày hợp lệ?
- 21. Làm thế nào tôi có thể sử dụng một biến như một tên biến trong Perl?
- 22. Làm thế nào tôi có thể chia chuỗi thành hai phần với Perl?
- 23. trong OpenMP, làm thế nào tôi có thể làm cho mỗi lõi đơn chạy một chuỗi?
- 24. Làm thế nào tôi có thể in chỉ một dòng mới unix trong Perl trên Win32?
- 25. làm thế nào tôi có thể phân tích một chuỗi json thành nsdictionary?
- 26. Làm thế nào để thay thế một chuỗi trong một tệp hiện có trong Perl?
- 27. Làm thế nào tôi có thể lưu trữ ảnh chụp regex trong một mảng trong Perl?
- 28. Làm thế nào tôi có thể tìm thấy số lượng khóa trong một băm trong Perl?
- 29. Extract ký tự K trước từ một chuỗi trong Perl
- 30. Làm thế nào tôi có thể bắt đầu ra từ một con cá chép trong Perl?
Mặc dù mọi phần tử trong mảng tạo SV với tất cả chi phí của nó. Bạn sẽ sử dụng nhiều bộ nhớ hơn theo cách này. –