c ve python daha 11 düzenli yavaş
Merhaba bölünmüş bir dize aşağıdaki kodu düzenli ifade kullanarak bölünmüş neden anlamak istiyorum
#include<regex>
#include<vector>
#include<string>
std::vector<std::string> split(const std::string &s){
static const std::regex rsplit(" ");
auto rit = std::sregex_token_iterator(s.begin(), s.end(), rsplit, -1);
auto rend = std::sregex_token_iterator();
auto res = std::vector<std::string>(rit, rend);
return res;
}
int main(){
for(auto i=0; i< 10000; i)
split("a b c", " ");
return 0;
}
daha yavaş daha sonra aşağıdaki python kodu
import re
for i in range(10000):
re.split(' ', 'a b c')
işte
> python test.py 0.05s user 0.01s system 94% cpu 0.070 total
./test 0.26s user 0.00s system 99% cpu 0.296 total
Im) üzerinde çınlama kullanarak.
derleme -O3 0.09s user 0.00s system 99% cpu 0.109 total
aşağı getiriyor
CEVAP
Dikkat edin
Ayrıca bu cevaba bakınız: temel olan http://stackoverflow.com/a/217082152 DÜZENLEYİNalt burada.
1000000 döngü daha iyi bir zamanlama ölçmek için artırılmış ettim.
Bu belki de benim zamanlama:
real 0m2.038s
user 0m2.009s
sys 0m0.024s
İşte kodunuz, biraz daha güzel bir eşdeğeri
#include <regex>
#include <vector>
#include <string>
std::vector<std::string> split(const std::string &s, const std::regex &r)
{
return {
std::sregex_token_iterator(s.begin(), s.end(), r, -1),
std::sregex_token_iterator()
};
}
int main()
{
const std::regex r(" ");
for(auto i=0; i < 1000000; i)
split("a b c", r);
return 0;
}
Zamanlama:
real 0m5.786s
user 0m5.779s
sys 0m0.005s
Bu vektör ve string nesneleri inşaat/ayırma önlemek için bir optimizasyon:
#include <regex>
#include <vector>
#include <string>
void split(const std::string &s, const std::regex &r, std::vector<std::string> &v)
{
auto rit = std::sregex_token_iterator(s.begin(), s.end(), r, -1);
auto rend = std::sregex_token_iterator();
v.clear();
while(rit != rend)
{
v.push_back(*rit);
rit;
}
}
int main()
{
const std::regex r(" ");
std::vector<std::string> v;
for(auto i=0; i < 1000000; i)
split("a b c", r, v);
return 0;
}
Zamanlama:
real 0m3.034s
user 0m3.029s
sys 0m0.004s
Bu 100% performans artışı yakındır.
Vektör döngü önce oluşturulur ve ilk yineleme bellek büyüyebilir. Daha sonra kaldırma hafızasında tutar ve dizeleri inşa bellek yokyerinde.
Başka bir performans artışı inşaat std::string
tamamen/bozulmaması için olacak, ve bu nedenle, ayırma nesneleri kaldırma/.
Bu yönde bir belirsiz
#include <regex>
#include <vector>
#include <string>
void split(const char *s, const std::regex &r, std::vector<std::string> &v)
{
auto rit = std::cregex_token_iterator(s, s std::strlen(s), r, -1);
auto rend = std::cregex_token_iterator();
v.clear();
while(rit != rend)
{
v.push_back(*rit);
rit;
}
}
Zamanlama:
real 0m2.509s
user 0m2.503s
sys 0m0.004s
Nihai bir gelişme const char *
std::vector
her char işaretçi s
orijinal içinde bir alt noktası yere dönmek gibi olurc dizekendisi. Asıl sorun, her boş sonlandırılmış (bunun için daha sonra bir örnek string_ref
1y C kullanımı) olmaz çünkü bunu yapamazsın.
Bu son gelişme de bu ile elde edilebilir:
#include <regex>
#include <vector>
#include <string>
void split(const std::string &s, const std::regex &r, std::vector<std::string> &v)
{
auto rit = std::cregex_token_iterator(s.data(), s.data() s.length(), r, -1);
auto rend = std::cregex_token_iterator();
v.clear();
while(rit != rend)
{
v.push_back(*rit);
rit;
}
}
int main()
{
const std::regex r(" ");
std::vector<std::string> v;
for(auto i=0; i < 1000000; i)
split("a b c", r, v); // the constant string("a b c") should be optimized
// by the compiler. I got the same performance as
// if it was an object outside the loop
return 0;
}
-O3 ile 3.3 (trunk) çınlama örnekleri yaptım. Belki diğer normal ifade kütüphaneler daha iyi yapabilir, ama her durumda, ayırma/deallocations sık bir performans isabet.
Boost.Normal ifade
Bunun için boost::regex
zamanlamac dizedeğişkenler örnek:
real 0m1.284s
user 0m1.278s
sys 0m0.005s
Aynı kodu, boost::regex
ve bu örnek std::regex
arayüzü ad değiştirmek ve eklemek için gerekli sadece aynıdır.
Bunun için en iyi zaman içinde daha iyi olsun dileklerini, C stdlib düzenli uygulamalar çok yenidir.
EDİT
Tamamlama uğruna, bu (yukarıda "son gelişme" öneri) ve bir şey std::vector<std::string> &v
eşdeğer sürümü geliştirilmiş performans değildi: . bahsedilen denedim
#include <regex>
#include <vector>
#include <string>
template<typename Iterator> class intrusive_substring
{
private:
Iterator begin_, end_;
public:
intrusive_substring(Iterator begin, Iterator end) : begin_(begin), end_(end) {}
Iterator begin() {return begin_;}
Iterator end() {return end_;}
};
using intrusive_char_substring = intrusive_substring<const char *>;
void split(const std::string &s, const std::regex &r, std::vector<intrusive_char_substring> &v)
{
auto rit = std::cregex_token_iterator(s.data(), s.data() s.length(), r, -1);
auto rend = std::cregex_token_iterator();
v.clear(); // This can potentially be optimized away by the compiler because
// the intrusive_char_substring destructor does nothing, so
// resetting the internal size is the only thing to be done.
// Formerly allocated memory is maintained.
while(rit != rend)
{
v.emplace_back(rit->first, rit->second);
rit;
}
}
int main()
{
const std::regex r(" ");
std::vector<intrusive_char_substring> v;
for(auto i=0; i < 1000000; i)
split("a b c", r, v);
return 0;
}
Bu array_ref and string_ref proposal ile bir ilgisi yoktur. İşte bir örnek kodu kullanma
#include <regex>
#include <vector>
#include <string>
#include <string_ref>
void split(const std::string &s, const std::regex &r, std::vector<std::string_ref> &v)
{
auto rit = std::cregex_token_iterator(s.data(), s.data() s.length(), r, -1);
auto rend = std::cregex_token_iterator();
v.clear();
while(rit != rend)
{
v.emplace_back(rit->first, rit->length());
rit;
}
}
int main()
{
const std::regex r(" ");
std::vector<std::string_ref> v;
for(auto i=0; i < 1000000; i)
split("a b c", r, v);
return 0;
}
Ayrıca string_ref
bir vektör yerine vektör dönüş split
durum string
kopya dönmek için daha ucuz olacaktır.
2 DÜZENLEYİN
Bu yeni çözüm getiri ile çıkış almak mümkün. Marshall ve Etkileşimleri (string_ref
yeniden var) kütüphanenin uygulama https://github.com/mclow/string_view bulunan string_view
kullandım.
#include <string>
#include <string_view>
#include <boost/regex.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/iterator/transform_iterator.hpp>
using namespace std;
using namespace std::experimental;
using namespace boost;
string_view stringfier(const cregex_token_iterator::value_type &match) {
return {match.first, static_cast<size_t>(match.length())};
}
using string_view_iterator =
transform_iterator<decltype(&stringfier), cregex_token_iterator>;
iterator_range<string_view_iterator> split(string_view s, const regex &r) {
return {
string_view_iterator(
cregex_token_iterator(s.begin(), s.end(), r, -1),
stringfier
),
string_view_iterator()
};
}
int main() {
const regex r(" ");
for (size_t i = 0; i < 1000000; i) {
split("a b c", r);
}
}
Zamanlama:
real 0m0.385s
user 0m0.385s
sys 0m0.000s
Bu önceki sonuçlara göre kaç not. Tabii ki, değil bir dolgu vector
döngünün içinde (ne eşleşen bir şey önceden muhtemelen çok), ama bir aralık neyse, dizi bitti dizi tabanlı for
, hatta kullanmak için bir dolgu vector
.
iterator_range
üzerinde değişen string
(veya . orijinal üzerinde string_view
s oluşturur gibi ^em>boş dize sonlandırıldıbu çok hafif olur, hiç gereksiz dize ayırma oluşturuluyor.
Sadece split
bu uygulama kullanarak, ama aslında bunu yapabiliriz vector
bir dolum karşılaştırmak için:
int main() {
const regex r(" ");
vector<string_view> v;
v.reserve(10);
for (size_t i = 0; i < 1000000; i) {
copy(split("a b c", r), back_inserter(v));
v.clear();
}
}
Bu kullanır aralığı kopya algoritmanın her tekrarında vektör doldurmak için destek, zamanlama:
real 0m1.002s
user 0m0.997s
sys 0m0.004s
Olarak görülebilir, ** 60 optimum çıkış param sürümü ile karşılaştırıldığında pek bir fark yok.
Not ayrıca bu şekilde çalışacak a proposal for a std::split
var.
Neden şiddetli bir dize Python C den d...
Neden bu Haskell program daha yavaş bi...
(Python) - daha basit bir yol yerine d...
Neden bir döngü iki döngü daha yavaş g...
Neden Standart girdiden okuma satır Py...