Здравствуйте, Андрей Хропов, Вы писали:
АХ>Странно почему boost себя так плохо показывает. АХ>Его вроде далеко не новички пишут, да и peer review у них вроде есть.
У них задачи другие. Они мозг тренируют.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
[Benchmark]:updated - Split на C++,D,C#,Nemerle,Boo,Java,Sca
Не удержался от того, чтобы создать новую расширенную версию.
Померил с использованием таймеров (чтобы не учитывать JIT компиляцию)
Вот результаты (усреднены по 10 запускам)
(Pentium M 1,7 Dothan + 768Mb DDR333)
:
Для стандартной библиотеки (и boost как ее продолжение для C++):
D(DMD) — 0.645 сек
D(GDC) — 0.653 сек
С#/Nemerle — 0.870 сек
Boo — 1.003 сек (*)
Python+Psyco — 1.451 сек
Python — 2.182 сек
Java/Scala — 3.470 сек
C++(GCC),boost,list,is_space — 10.045 сек (**)
C++(MS),boost,list,is_space — 12.708 сек (**)
* для Boo почему-то не работает Split(" "), а только Split(),
поэтому неск медленнее
** взят лучший несамодельный вариант
Самоделки : Nemerle-Tokenizer — 0.738 сек
Nemerle-withLists — 0.896 сек
Java-Bicycle — 1.369 сек
Java-Tokenizer — 2.119 сек
C++(MS),Noname2,list,functor,ref — 2.463 сек (*)
Scala-Tokenizer — 2.642 сек
Scala-withLists — 2.785 сек
C++(GCC),VK,list,functor,val — 3.896 сек (*)
* взят наилучший из самодельных вариантов для данного компилятора
import System;
import System.Diagnostics;
stopwatch = Stopwatch();
stopwatch.Start();
res = 0;
for i in range(1000000):
res += "123 345 asdf 23453 asdfas".Split().Length;
stopwatch.Stop();
Console.WriteLine("Boo: res is ${res}, ${stopwatch.Elapsed} elapsed");
Java:
import java.io.*;
import java.util.*;
class splitjava {
public static void main(String[] args) {
long start = System.nanoTime();
int res = 0;
for(int i = 0;i < 1000000;i++)
res += "123 345 asdf 23453 asdfas".split(" ").length;
long stop = System.nanoTime();
System.out.println("Java-StdLib: res = " + res + ", " + ((double)(stop - start) / 1.0e6) + " ms elapsed");
}
}
Scala:
import java.io;
import java.util;
object splitscala {
def main(args : Array[String]) = {
val start = System.nanoTime();
var res = 0;
for (val i <- Iterator.range(0, 1000000))
res = res + "123 345 asdf 23453 asdfas".split(" ").length;
val stop = System.nanoTime();
System.out.println("Scala-StdLib: res = " + res + ", " + ((stop - start) / 1.0e6) + " ms elapsed");
}
}
import java.io.*;
import java.util.*;
class SplitNoname2 {
private static int testTokenizer() {
int answer = 0;
for (int i = 0; i < 1000000; i++) {
final List<String> list = new ArrayList<String>();
final String text = "123 345 asdf 23453 asdfas".intern();
for (final StringTokenizer strtok = new StringTokenizer(text);
strtok.hasMoreTokens(); list.add(strtok.nextToken())) ;
answer += list.size();
}
return answer;
}
private static int testNoname2() throws UnsupportedEncodingException {
int answer = 0;
final byte space = " ".getBytes("windows-1251")[0];
for (int i = 0; i < 1000000; i++) {
final List<String> array = new ArrayList<String>();
final String text = "123 345 asdf 23453 asdfas".intern();//.getBytes("windows-1251");final int clen = text.length();
for (int c = 0, x = 0; c < clen; c++) {
if (text.charAt(c) == space) {
array.add( text.substring(x, c));
x = c + 1;
} else if (c == clen - 1 && clen - x > 1) {
array.add( text.substring(x, clen) );
}
}
answer += array.size();
}
return answer;
}
public static void main(String [] args) throws UnsupportedEncodingException {
long start = System.nanoTime();
int res = testTokenizer();
long stop = System.nanoTime();
System.out.println("Java-Tokenizer: res = " + res + ", " + ((double)(stop - start) / 1.0e6) + " ms elapsed");
start = System.nanoTime();
res = testNoname2();
stop = System.nanoTime();
System.out.println("Java-Noname2: res = " + res + ", " + ((double)(stop - start) / 1.0e6) + " ms elapsed");
}
}
import java.io;
import java.util;
import System.out._
object SplitVlad
{
def SplitToList(str : String) : List[String] = {
def loop(start : Int, i : Int, lst : List[String] ) : List[String] = {
if(i < str.length)
str(i) match
{
case ' ' => str.substring(start, i) :: loop(i + 1, i + 1, lst);
case _ => loop(start, i + 1, lst);
}
else if (start == i) lst;
else List(str.substring(start, i));
};
loop(0, 0, Nil);
}
def Tokenize(str : String) = new Iterator[String]{
var start : Int = 0
var i : Int = 0
var r : String = "";
def hasNext : boolean =
{
if (i < str.length)
str(i) match
{
case ' ' =>
r = str.substring(start, i);
i = i + 1; start = i;
true;
case _ =>
i = i + 1;
hasNext;
}
else if (start != i) { r = str.substring(start, i); start = i; true }
else false
}
def next = r;
}
def main(args : Array[String]) = {
// check
print("SplitToList: [");
for(val s <- SplitToList("123 345 asdf 23453 asdfas") )
print(s + ",");
print("]\n");
print("Tokenizer: [");
for(val s <- Tokenize("123 345 asdf 23453 asdfas") )
print(s + ",");
print("]\n");
var start = System.nanoTime();
var res = 0;
for (val i <- Iterator.range(0, 1000000))
res = res + SplitToList("123 345 asdf 23453 asdfas").length;
var stop = System.nanoTime();
println("Scala-SplitToList: res = " + res + ", " + ((stop - start) / 1.0e6) + " ms elapsed");
start = System.nanoTime();
res = 0;
for (val i <- Iterator.range(0, 1000000))
for(val s <- Tokenize("123 345 asdf 23453 asdfas") )
res = res + 1;
stop = System.nanoTime();
println("Scala-Tokenizer: res = " + res + ", " + ((stop - start) / 1.0e6) + " ms elapsed");
}
}
По сравнению с Nemerle мне показалось менее выразительным:
1) Генераторы реализуются довольно неизящно
2) Для рекурсивно вызываемых функций type inference не работает
3) Синтаксис pattern-matching а более громоздкий
C++: разные варианты с boost + взяты самоделки от VK
+
опробованы и разными вариантами (функторы и функции, передача предикатов по ссылке и по значению):
#include <list>
#include <vector>
#include <string>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <windows.h> // for GetTickCountusing namespace std;
using namespace boost::algorithm;
class SplitNoname2
{
public:
template <class C, class P>
inline static void SplitVal(C& tokens, const string& str, P is_delimiter)
{
size_t inpSize = str.size();
for (size_t c = 0, x = 0; c < inpSize; ++c ) {
if( is_delimiter(str[c]) ) {
tokens.push_back( str.substr(x,c-x) );
x = c + 1;
} else if (c == inpSize - 1 && inpSize - x > 1) {
tokens.push_back( str.substr(x,inpSize-x) );
}
}
}
template <class C, class P>
inline static void SplitRef(C& tokens, const string& str, const P& is_delimiter)
{
size_t inpSize = str.size();
for (size_t c = 0, x = 0; c < inpSize; ++c ) {
if( is_delimiter(str[c]) ) {
tokens.push_back( str.substr(x,c-x) );
x = c + 1;
} else if (c == inpSize - 1 && inpSize - x > 1) {
tokens.push_back( str.substr(x,inpSize-x) );
}
}
}
};
class SplitVK
{
public:
template <class C, class P>
inline static void SplitVal(C& tokens, const string& str, P is_delimiter)
{
typename string::const_iterator it = str.begin(), token_start = it, end = str.end();
for(; it != end; ++it)
{
if (is_delimiter(*it))
{
if (token_start != it)
tokens.push_back(string(token_start, it));
++(token_start = it);
}
}
if (token_start != it)
tokens.push_back(string(token_start, it));
}
template <class C, class P>
inline static void SplitRef(C& tokens, const string& str, const P& is_delimiter)
{
typename string::const_iterator it = str.begin(), token_start = it, end = str.end();
for(; it != end; ++it)
{
if (is_delimiter(*it))
{
if (token_start != it)
tokens.push_back(string(token_start, it));
++(token_start = it);
}
}
if (token_start != it)
tokens.push_back(string(token_start, it));
}
};
class MyIsSpace
{
public:
inline bool operator()(char c) const { return c == ' '; }
};
inline bool myIsSpace(char c){ return c == ' '; }
template<class C, class Pred>
inline void TestBoost( const string& testName, Pred pred )
{
DWORD start = GetTickCount();
string str = "123 345 asdf 23453 asdfas";
size_t res = 0;
for(int i = 0; i < 1000000; i++)
{
C tokens;
split(tokens, str, pred);
res += tokens.size();
}
DWORD stop = GetTickCount();
cout << "C++,boost," << testName << ": res is " << res << ',' << stop - start << " ms elapsed\n";
}
template<class Splitter, class C, class Pred>
inline void Test( const string& testName, Pred pred )
{
DWORD start = GetTickCount();
const string str = "123 345 asdf 23453 asdfas";
size_t res = 0;
for(int i = 0; i < 1000000; i++)
{
C tokens;
Splitter::SplitVal(tokens, str, pred );
res += tokens.size();
}
DWORD stop = GetTickCount();
cout << "C++," << testName << ",val: res is " << res << ',' << stop - start << " ms elapsed\n";
start = GetTickCount();
res = 0;
for(int i = 0; i < 1000000; i++)
{
C tokens;
Splitter::SplitRef(tokens, str, pred );
res += tokens.size();
}
stop = GetTickCount();
cout << "C++," << testName << ",ref: res is " << res << ',' << stop - start << " ms elapsed\n";
}
int main()
{
TestBoost< vector<string> >("vector,is_any_of", is_any_of(" ") );
TestBoost< list<string> >("list,is_any_of", is_any_of(" ") );
TestBoost< vector<string> >("vector,is_space", is_space() );
TestBoost< list<string> >("list,is_space", is_space() );
TestBoost< vector<string> >("vector,myIsSpace", myIsSpace );
TestBoost< list<string> >("list,myIsSpace", myIsSpace );
Test< SplitVK,vector<string> >("VK,vector,function", myIsSpace);
Test< SplitVK,list<string> >("VK,list,function", myIsSpace);
Test< SplitNoname2,vector<string> >("Noname2,vector,function", myIsSpace);
Test< SplitNoname2,list<string> >("Noname2,list,function", myIsSpace);
Test< SplitVK,vector<string> >("VK,vector,functor", MyIsSpace() );
Test< SplitVK,list<string> >("VK,list,functor", MyIsSpace() );
Test< SplitNoname2,vector<string> >("Noname2,vector,functor", MyIsSpace() );
Test< SplitNoname2,list<string> >("Noname2,list,functor", MyIsSpace() );
return 0;
}
а вот полные таблицы результатов для компилятора от MS(VC++ 8) и GCC (3.4.2 под MinGW):
MS:
C++,boost,vector,is_any_of: 23914 ms elapsed
C++,boost,list,is_any_of: 21801 ms elapsed
C++,boost,vector,is_space: 14842 ms elapsed
C++,boost,list,is_space: 12708 ms elapsed
C++,boost,vector,myIsSpace: 7220 ms elapsed
C++,boost,list,myIsSpace: 5298 ms elapsed
C++,VK,vector,function,val: 4887 ms elapsed
C++,VK,vector,function,ref: 4857 ms elapsed
C++,VK,list,function,val: 2594 ms elapsed
C++,VK,list,function,ref: 2613 ms elapsed
C++,Noname2,vector,function,val: 4837 ms elapsed
C++,Noname2,vector,function,ref: 4847 ms elapsed
C++,Noname2,list,function,val: 2554 ms elapsed
C++,Noname2,list,function,ref: 2534 ms elapsed
C++,VK,vector,functor,val: 4797 ms elapsed
C++,VK,vector,functor,ref: 4777 ms elapsed
C++,VK,list,functor,val: 2513 ms elapsed
C++,VK,list,functor,ref: 2514 ms elapsed
C++,Noname2,vector,functor,val: 4747 ms elapsed
C++,Noname2,vector,functor,ref: 4746 ms elapsed
C++,Noname2,list,functor,val: 2474 ms elapsed
C++,Noname2,list,functor,ref: 2463 ms elapsed
GCC:
C++,boost,vector,is_any_of: 16633 ms elapsed
C++,boost,list,is_any_of: 15893 ms elapsed
C++,boost,vector,is_space: 10515 ms elapsed
C++,boost,list,is_space: 10045 ms elapsed
C++,boost,vector,myIsSpace: 7070 ms elapsed
C++,boost,list,myIsSpace: 6329 ms elapsed
C++,VK,vector,function,val: 4737 ms elapsed
C++,VK,vector,function,ref: 4797 ms elapsed
C++,VK,list,function,val: 4076 ms elapsed
C++,VK,list,function,ref: 4036 ms elapsed
C++,Noname2,vector,function,val: 4997 ms elapsed
C++,Noname2,vector,function,ref: 4997 ms elapsed
C++,Noname2,list,function,val: 4246 ms elapsed
C++,Noname2,list,function,ref: 4256 ms elapsed
C++,VK,vector,functor,val: 4647 ms elapsed
C++,VK,vector,functor,ref: 4606 ms elapsed
C++,VK,list,functor,val: 3896 ms elapsed
C++,VK,list,functor,ref: 3946 ms elapsed
C++,Noname2,vector,functor,val: 4887 ms elapsed
C++,Noname2,vector,functor,ref: 4877 ms elapsed
C++,Noname2,list,functor,val: 4116 ms elapsed
C++,Noname2,list,functor,ref: 4196 ms elapsed
Видно, что выгоднее использовать функторы (немного) и намного выгоднее списки (для особенно для MS)
Здравствуйте, Denis2005, Вы писали:
D>Зачем мне питон, когда такой пример под .NET отрабатывает за 0.6 сек, и код даже короче (на C#_, чем в приведенном примере.
От это ты зря здесь сказал. Сейчас подтянутся eao197 с ГВ и после короткой но продолжительной бесебы в тебе найдут массу недостатков.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD>Пардон. Забыл ссылку дать. Вот этот код мне больше всего понравился. Истенно в духе С++, т.е. пол лохунгом "зато быстро!". VD>Re: Наколенный вариант 8-летней давности
Если бы ты был чуть более внимательным, то заметил бы, что тот мой код (напомню — востмилетней давности) умеет еще выполнять trim по ходу дела, выделять токены в кавычках любого вида (аргумент "quote") с маскированием (аргумент mask_chr) и работать с тремя типами разделителей:
single — каждый символ является разделителем (1,,,2 выдаст "1" "" "" "2")
multiple — работает как strtok (1,,,2 выдаст "1" "2")
whole_str — разделителем является вся строка
Все это не нужно в рамках задачи данного треда, но при этом и не мешает. Просто я наивно расчитывал на наличие у тебя некоторых зачатков разума.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, cattus, Вы писали:
C>>Аналогичная скорость выполнения достигается на Lispe CMUCL, SBCL, если код реализуется в виде макры.
C>Поигравши с лисповыми макрами, мой друг улучьшил время выполнения кода до 0 мс, притом время выполнения совершенно не зависит от N. ))
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, VladD2, Вы писали:
VD>>Он на Руби пишет, в лучшем случае. А там как и в С++ ООП основное средство декомпозиции. Других практически нет. Одними лямбдами (блоками) сыт не будешь.
E>Ага, а тебе еще паттерн-матчинг добавили. Он рулит покруче ООП и лямб вместе взятых.
Все-таки паттерн матчинг вещь в хозяйстве полезная, неплохо было бы если бы его ввели в питон, да и в руби бы не помешал, притом для ввода например в питон даже не надо больших уж затрат и ломки старого кода, достаточно одного ключевого слова. Ну а пока не ввели, я тут играюсь библиотечными методами, вот например такой эскизик сегодня нарисовал:
class when:
patterns = []
def __init__(self, expr):
when.patterns.append(self)
self.expr = expr
def __call__(self, func):
arg0 = tuple(getargspec(func)[0])
self.func = func
def _wrap(*args):
d = dict(zip(arg0, args))
for pattern in when.patterns:
if pattern.func.__name__ == func.__name__ and eval(pattern.expr, globals(), d):
return pattern.func(*args)
raise TypeError("not find pattern: " + repr(d))
return _wrap
использование:
@when("n < 2")
def fib(n):
return 1
@when("n >= 2")
def fib(n):
return fib(n - 1) + fib(n - 2)
print fib(8)
@when("a == 0")
def ack(a, b):
return b + 1
@when("a != 0 and b == 0")
def ack(a, b):
return ack( a - 1, 1 )
@when("True")
def ack(a, b):
return ack( a - 1, ack( a, b - 1 ) );
print ack(3, 4)
Так что если очень хочется то и паттерн матчинг можно сделать
Померил с использованием таймеров (чтобы не учитывать JIT компиляцию)
Вот результаты (усреднены по 10 запускам)
(Athlon XP 1700+ @ 1.5 GHZ + 512Mb DDR266)
:
Компиляторы:
DMD — Digital Mars D 0.166
GDC — GNU D Compiler 0.19 для MinGW 3.4.2
C# — MS C# Compiler в составе VS2005
Nemerle — 0.9.3.99(svn) (от 12.09)
Python 2.4.2
Python 2.4.2 + Psyco 1.5
GCC — GCC 3.4.2 (в виде MinGW) + Boost 1.33.1
MS VC++ — MS C++ Compiler в составе VS2005 + Boost 1.33.1
import std.stdio, std.string, std.perf;
void main()
{
auto t = new HighPerformanceCounter();
t.start();
uint res = 0;
for(uint i = 0; i < 1000000; ++i)
res += split("123 345 asdf 23453 asdfas"," ").length;
t.stop();
writefln("res is ", res ," ", t.milliseconds()," ms elapsed.");
}
C#:
using System;
using System.Diagnostics;
class Runner
{
public static void Main()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int res = 0;
for(uint i = 0; i < 1000000; ++i)
res += "123 345 asdf 23453 asdfas".Split(' ').Length;
stopwatch.Stop();
Console.WriteLine("res is {0}, {1} elapsed",
res, stopwatch.Elapsed);
}
}
Nemerle:
using System.Console;
using System.Diagnostics;
def stopwatch = Stopwatch();
stopwatch.Start();
mutable res = 0;
repeat(1000000)
res += "123 345 asdf 23453 asdfas".Split(' ').Length;
stopwatch.Stop();
WriteLine($"res is $res, $(stopwatch.Elapsed) elapsed");
Python:
import time
start = time.clock()
res = 0
for i in xrange(1000000):
res += len("123 345 asdf 23453 asdfas".split(" "))
finish = time.clock()
print 'res is %s, %f sec elapsed' % ( res, finish - start )
Python+Psyco:
import time
import psyco
psyco.full()
start = time.clock()
res = 0
for i in xrange(1000000):
res += len("123 345 asdf 23453 asdfas".split(" "))
finish = time.clock()
print 'res is %s, %f sec elapsed' % ( res, finish - start )
С++:
#include <vector>
#include <string>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <windows.h> // for GetTickCountusing namespace std;
using namespace boost::algorithm;
int main()
{
DWORD start = GetTickCount();
int res = 0;
for(int i = 0; i < 1000000; i++)
{
// так корректней сравнивать, ведь в др программах мы размер не указывали
// + по моим тестам почти не повлияло на скорость
vector<string> tokens;
split(tokens, "123 345 asdf 23453 asdfas", is_any_of(" "));
res += tokens.size();
}
DWORD stop = GetTickCount();
cout << "res is " << res << ',' << stop - start << " ms elapsed\n";
return 0;
}
Re: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Я уж тут подумал на кривизну рук, но пишу/писал на C++ достаточно долго, еще с первых GCC, TCPP 1.0, ..., и с оптимизаторами знаком не понаслышке. D>[Есть подозрение на неграмотное дефолтовое аллокирование std::vector и std::string.]
Вряд ли тут аллокаторы помогут. Тут просто сами строки неправильные. Попробуй поискать реализации const_string наверно будет шустрее. Кстати от компилятора сильно зависит, vc71 отработал у меня за 22 секунды, а gcc3.4 за 7.
D>Кстати .NET-ий JIT в Release-е особо не 'химичил' с этим кодом, и честно вызывал split для константной строки и далее inline-ил вызов get_Length() на возвращенном строковом массиве;
D>Пока переписал с исп. strtok и сделал запасной вариант под .NET. D>Может есть что сказать приверженцам BOOST-а, и по возможности объяснить где "кривые руки"?
на питон переходи, вот такой код:
r = 0
for i in xrange(1000000):
r += len("123 345 asdf 23453 asdfas".split(" "))
print r
отрабатывает за 2.5 секунды
Re[5]: BOOST, .NET, String.Split и производительность…
Здравствуйте, McSeem2, Вы писали:
MS>Во-во. Я тоже с этим сталкивался — isspace на винде отъедал больше половины всего времени работы парсера. Так что язык здесь ни при чем вообще.
Естественно. Причем библиотеки. Только вот когда любители С++ начинают пенесометрией по скорости заниматься они как-то забывают, что в программе многое от библиотек зависит и все время приводят вручную оптимизированный код. А пожизни в программах может быть уйма вот таких проблемочек которые в купе вырастают в торомоза. Так что лучший друг производительности по прежнему не С++, а профайлер.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: BOOST, .NET, String.Split и производительность…
Здравствуйте, WolfHound, Вы писали:
E>>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера. WH>Код в студию.
Вот, пример большого функтора:
/*!
\since v.4.2.7
\brief Предикат для std::find_if.
Для очередного состояния проверяет возможность слияния
с состоянием из другого класса агентов.
Определяет, есть ли среди всех классов, на которые ссылаются
состояния, еще не полностью определенные классы.
*/class merge_possibility_checker_t
: public std::unary_function<
const state_handler_impl_ptr_vector_t::value_type &,
bool >
{
private :
/*! Список всех классов. */const class_map_t & m_all_classes;
/*! Список состояний всех классов */const std_class_relation_handler_t::class_info_map_t &
m_classes_state;
/*! Принимает значение true, если были найдены не
полностью определенные классы. */bool & m_is_incomplete_class_found;
/*! Приемник описания ошибки. */
std::string & m_error_desc;
public :
//! Основной конструктор.
merge_possibility_checker_t(
//! Список всех классов.const class_map_t & all_classes,
const std_class_relation_handler_t::class_info_map_t &
classes_state,
bool & is_incomplete_class_found,
//! Приемник описания ошибки.
std::string & error_desc )
: m_is_incomplete_class_found( is_incomplete_class_found )
, m_all_classes( all_classes )
, m_classes_state( classes_state )
, m_error_desc( error_desc )
{}
result_type
operator()( argument_type a );
private :
/*! Проверка наличия указанного состояния в указанном
классе.
\return true, если состояние найдено. */bool
try_find_state_in_class(
//! Имя искомого состояния.const std::string & state_name,
//! Класс, в котором состояние нужно найти.const class_handler_impl_t & class_handler );
};
merge_possibility_checker_t::result_type
merge_possibility_checker_t::operator()( argument_type a )
{
bool result = false;
const state_handler_impl_t::merge_list_t & merge_list =
a->merge_list();
for( state_handler_impl_t::merge_list_t::const_iterator
it = merge_list.begin(), it_end = merge_list.end();
it != it_end;
++it )
{
bool is_merge_valid = false;
const state_handler_impl_t::merge_t & m = *it;
// Должен быть известен класс.
class_map_t::const_iterator it_class = m_all_classes.find(
m.m_class_name );
if( it_class != m_all_classes.end() )
{
int state = m_classes_state.find(
m.m_class_name )->second.m_state;
// Класс должен быть полностью определен.if( std_class_relation_handler_t::state_valid == state )
{
// Должно быть известно состояние.if( try_find_state_in_class(
m.m_state_name, *( it_class->second ) ) )
// Все хорошо. Поэтому, чтобы перейти к обработке
// следующего состояния, нужно возвратить false.
is_merge_valid = true;
else
{
// Состояние не известно.
m_error_desc += std::string( "state '" ) +
a->query_name() +
"' requires merging with undefined state '" +
m.m_state_name + "' from class '" +
m.m_class_name + "';";
}
}
else if( std_class_relation_handler_t::state_invalid == state )
// Нашли ссылку на некорректный класс.
m_error_desc += std::string( "state '" ) +
a->query_name() +
"' requires merging with invalid class '" +
m.m_class_name + "';";
else
{
// Класс еще не определен.
m_is_incomplete_class_found = true;
m_error_desc += std::string( "incomplete class: " ) +
m.m_class_name + ";";
}
}
else// Нашли ссылку на неизвестный класс.
m_error_desc += std::string( "state '" ) + a->query_name() +
"' requires merging with undefined class '" +
m.m_class_name + "';";
// Если текущее слияние не корректно, то и состояние не может
// быть корректным.if( !is_merge_valid )
result = true;
}
return result;
}
bool
merge_possibility_checker_t::try_find_state_in_class(
const std::string & state_name,
const class_handler_impl_t & class_handler )
{
const state_handler_impl_ptr_vector_t & states =
class_handler.query_state_handlers();
return ( states.end() != std::find_if(
states.begin(), states.end(),
state_by_name_finder_t( state_name ) ) );
}
который используется так:
int
std_class_relation_handler_t::try_merge_states(
const class_handler_impl_t & class_handler,
const class_map_t & all_classes,
std::string & error_desc )
{
// Берем все состояния, которые нуждаются в слиянии.
state_handler_impl_ptr_vector_t states_for_merging =
class_handler.states_for_merge();
// Проверяем возможность проведения слияния.bool is_incomplete_class_found = false;
merge_possibility_checker_t checker( all_classes, m_classes,
is_incomplete_class_found, error_desc );
if( states_for_merging.end() != std::find_if(
states_for_merging.begin(), states_for_merging.end(),
checker ) )// Слияние не возможно. Осталось только определить,
// по какой причине.return ( is_incomplete_class_found ?
state_not_processed :
state_invalid );
// Выполняем слияние.
std::for_each( states_for_merging.begin(),
states_for_merging.end(),
merge_maker_t( all_classes ) );
return state_valid;
}
По поводу наследования: в своих OpenSource проектах с ходу не нашел. А код из закрытых проектов не смотрел, т.к. результат все равно не смогу показать. Но раз или два пришлось делать наследование для функторов, чтобы общую функциональность в базовый класс поместить. Ну и простейший пример наследования для функторов -- наследование от std::unary_function .
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[11]: BOOST, .NET, String.Split и производительность…
Здравствуйте, vdimas, Вы писали:
WH>>А Obj.Prop1.Prop2.Prop3 это крупный или мелкий случай? V>для этого есть var().
Я думаю WolfHound совсем не "это" имел в виду. Он говорил о доступе к членам параметра лямбды. А с этим у boost::lambda совсем туго, и иначе и быть не может. Вместо таких безобразий:
_1 ->* &B::foo
bind(&A::data, _1)
На Nemerle можно написать:
_.foo
_.data
Что делать в случае obj.Prop1.Prop2.Prop3 для boost::lambda я затрудняюсь сказать, но что-то мне подсказывает, что ничего хорошего сделать здесь нельзя. А вот на Nemerle это просто:
obj => obj.Prop1.Prop2.Prop3
V>Понял, в чем прикол? V>В общем, var явным образом определяет границы замыкания.
Скорее var здесь создает иллюзию замыкания. Если значение, на которое этот var ссылается умрет, то думаю все накроется медным тазом. А если подсунуть ему rvalue, то просто не скомпилируется.
V>А на Nemerle как это сделать элегантно?
По-моему на Nemerle лучше "этого" не делать, так как весьма сомнительная это вещь. Ничего кроме усложнения понимания кода она не несет.
Вот скажем слегка измененный пример из документации:
int index = 0;
for_each(a.end(), a.end(), cout << ++index << ':' << _1 << '\n');
Нормальная лямбда с нормальными замыканиями не напечатала бы ничего. А это недоразумение естественно напечатает 1:. А var это всего лишь костыль для частичного обхода подобных случаев.
Так что не нужно нам таких "элегантных" способов. В Nemerle есть нормальные замыкания, а если понадобится подобная сомнительная вещь, то можно будет сделать — язык вполне позволяет.
Ну, раз пошла такая пьянка грех не порекламировать Nemerle .
Вот написал это никчемный тестик. Причем разными спосбами чтобы оценить насколько дорого обходится функционалщина и другие хайтек-изыски в современных языках. Особенноп риятно этот тест сравнивать с вот этоим произведением человеческой мысли .
Первый результат — это рукописный Split возвращающий (какой ужас!) динамический списко (то есть на каждый жлемент списка создается по дополнительному объекту с указателем на следующий элемент. Размет каждого доп. объекта 16 байт). Ко всему прочему этот метод строит прямой список для чего ему приходится использовать стек (не использовать концевую рекурсию). Так же для вычисления длинны списка свойство Length делет (ужас то какой!) еще один проход по списку.
Второй результат — это токенайзер возвращающий позицию токена. Интересен он тем, что использует конструкцию yield (то есть является континюэшоном).
Третий результат — это библиотечный метод Split().
А теперь код:
using System.Console;
using System.Diagnostics.Stopwatch;
module Parse
{
public Split(this str : string) : list[string]
{
def loop(start, i, lst)
{
if (i < str.Length)
match (str[i])
{
| ' ' | '\t' => str.Substring(start, i - start) :: loop(i + 1, i + 1, lst)
| _ => loop(start, i + 1, lst)
}
else if (start == i) lst
else [str.Substring(start, i - start)];
}
loop(0, 0, []);
}
public Tokenize(this str : string) : System.Collections.Generic.IEnumerable[(int * int)]
{
def loop(start, i)
{
if (i < str.Length)
match (str[i])
{
| ' ' | '\t' =>
yield (start, i - start);
loop(i + 1, i + 1)
| _ => loop(start, i + 1)
}
else if (start != i) yield (start, i - start)
else ()
}
loop(0, 0);
}
}
////////////////////////// Далее идут тесты /////////////////////////////////
WriteLine(Parse.Split("123 345 asdf 23453 asdfas"));
/////////////////////////////////////////////////////////////////////////////
// Тестируем сплит написанный что называется в стиле "мама не горюй" (с динамическими списками).
def timer = StartNew();
mutable count = 0;
for(mutable i = 0; i < 1000000; ++i)
count += Parse.Split("123 345 asdf 23453 asdfas").Length;
WriteLine(timer.Elapsed);
WriteLine(count);
/////////////////////////////////////////////////////////////////////////////
// Тестируем бибилиотечный сплит.
def timer = StartNew();
count = 0;
for(mutable i = 0; i < 1000000; ++i)
foreach (_ in Parse.Tokenize("123 345 asdf 23453 asdfas"))
count++;
WriteLine(timer.Elapsed);
WriteLine(count);
/////////////////////////////////////////////////////////////////////////////
// Тестируем токенайзер.
def timer = StartNew();
count = 0;
for(mutable i = 0; i < 1000000; ++i)
count += "123 345 asdf 23453 asdfas".Split().Length;
WriteLine(timer.Elapsed);
WriteLine(count);
_ = ReadLine();
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Доброго времени суток!
D>Понадобилось 'посплитить' строки (вообще задача более сложная, но обо всем по порядку), и по совету “мудрых старцев” (которые по новомодной традиции, при каждом чихе отправляют к boost-у) решил потестировать производительность boost::algoruthm:split.
D>Честно говоря, результаты меня обескуражили…
на сколько я понял очень много жрёт split_iterator который наследуется от find_iterator_base который в свою очередь принимает предикат который внутри хранится... Внимание! вот таким вот образом
Здравствуйте, FR, Вы писали:
FR>Все-таки паттерн матчинг вещь в хозяйстве полезная, неплохо было бы если бы его ввели в питон, да и в руби бы не помешал, притом для ввода например в питон даже не надо больших уж затрат и ломки старого кода, достаточно одного ключевого слова. Ну а пока не ввели, я тут играюсь библиотечными методами, вот например такой эскизик сегодня нарисовал:
Здравствуйте, Denis2005, Вы писали:
D>Честно говоря, результаты меня обескуражили…
D>Время работы: 20 секунд. (и это при полной оптимизации и отключенными проверками !?!) D>Может есть что сказать приверженцам BOOST-а, и по возможности объяснить где "кривые руки"?
По моему беглому взгляду на реализацию split-а показалось, что дело в реализации is_any_of. В частности, в том, что при каждом обращении к split объект-предикат, который скрывается за is_any_of конструируется заново. И более того, где-то там внутри этот предикат передается в подчиненные функции и сохраняется во вспомогательных объектах по значению.
Образно говоря, происходит что-то похожее на нижеследующий код:
#include <algorithm>
#include <string>
#include <set>
template< class Finder >
class Finder_Holder
{
private :
Finder finder_;
public :
Finder_Holder( Finder finder )
: finder_( finder )
{}
void
operator()( char c ) { finder_( c ); }
};
class Finder
{
private :
std::set< char > tokens_;
public :
Finder( std::string tokens )
: tokens_( tokens.begin(), tokens.end() )
{}
bool
operator()( char c )
{
return tokens_.end() == tokens_.find( c );
}
};
Finder_Holder< Finder >
is_any_of( const std::string & value )
{
return Finder_Holder< Finder >( Finder( value ) );
}
template< class Predicate >
void
do_something( const std::string & s, Predicate pred )
{
std::for_each( s.begin(), s.end(), pred );
}
void
test()
{
for( int i = 0; i != 1000000; ++i )
do_something( "123 345 asdf 23453 asdfas", is_any_of( " " ) );
}
int
main()
{
test();
return 0;
}
Обратите внимание на то, что в do_something объект pred передается по значению. А is_any_of возвращает объект Finder_Holder так же по значению.
В результате этот код у меня работает за время:
bash-3.1$ time t1.exe
real 0m5.172s
user 0m0.031s
sys 0m0.000s
(cl -O2 -EHsc)
Если же сделать так. чтобы по максимуму сохранять ссылки на объекты:
#include <algorithm>
#include <string>
#include <set>
template< class Finder >
class Finder_Holder
{
private :
const Finder & finder_;
public :
Finder_Holder( const Finder & finder )
: finder_( finder )
{}
void
operator()( char c ) const { finder_( c ); }
};
class Finder
{
private :
std::set< char > tokens_;
public :
Finder( const std::string & tokens )
: tokens_( tokens.begin(), tokens.end() )
{}
bool
operator()( char c ) const
{
return tokens_.end() == tokens_.find( c );
}
};
Finder_Holder< Finder >
is_any_of( const std::string & value )
{
return Finder_Holder< Finder >( Finder( value ) );
}
template< class Predicate >
void
do_something( const std::string & s, const Predicate & pred )
{
std::for_each( s.begin(), s.end(), pred );
}
void
test()
{
const Finder_Holder< Finder > pred = is_any_of( " " );
for( int i = 0; i != 1000000; ++i )
do_something( "123 345 asdf 23453 asdfas", pred );
}
int
main()
{
test();
return 0;
}
то получается время:
bash-3.1$ time t2.exe
real 0m0.406s
user 0m0.015s
sys 0m0.015s
при тех же опциях компилятора.
Очень похоже, что именно из-за проблем с is_any_of и наблюдаются тормоза в твоем случае.
А любителям boost-ов я бы напомнил: KISS
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, cattus, Вы писали:
C>>Вот еще одно подтверждение изначальной ущербности теста. Прошу сильно не пинать за код -- я очень долго ничего не писал на Haskell'е.
FR>Тест конечно ущербный, но это уже чистый мухлежь :) FR>Просто нужно переписать не с миллионом повторов, а с миллион раз размноженной строкой:
Ну почему же мухлеж. Ведь мы не знаем ;)), как работает оптимизатор в С++, в D или где-то еще. Данный код на хаскеле полностью соответствует задаче поставленной в тесте и структурно, в основных своих частях, похож на код тестов реализованных на других языках. Никто не запрещает другим компиляторам или интерпретаторам оптимизировать код, зачем запрещать делать это ghc или SBCL'ю.
Здравствуйте, cattus, Вы писали:
C>Все вопросы к реализации MinGW. И вообще, тестировать надо под нормальными операционками, а не под тормозами от дяди Билла.
Ну, вот мы и выяснили в чем проблема С++. Проблема как всегда в деде Билле. Если бы не он, то буст был бы в 30 раз быстрее и удобнее. Я всегда знал что это ЗАГОВОР!
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: BOOST, .NET, String.Split и производительность…
) который работает с теми же string и создает их на каждый чих, получается гораздо шустрее чем с boost::algorithm::split? FR>Да и скрипты и шарп и D тоже создают строки и обгоняют буст без проблем.
А разве это не очевидно? Потому, что вместо выпендрежа люди просто писали библиотеки для реальной работы. А те кто писал бустовский сплит основной целью ставили сделать красиво на С++. Цель то была доказать тезис о том, что С++ настолько крут, что в нем все можно сделать в бибилотеке... и лямбду, и замыкание, и черта лысого. Меж тем если выбростиь все навороты, то написать шустрый сплит на С++ не составляет пробелмы.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Насчет черта лысого не уверен, но лямбда удалась на славу:
D>
D>void MyF1(vector<int>& vec, int s)
D>{
D> transform(vec.begin(), vec.end(), vec.begin(), (s + _1));
D>}
D>
Вот скажи мне на сколько часто тебе нужны такая лямюбда? Мне нужно как минимум обратится к челену класса, а с этим уже все не так красиво... А если нужно както так Obj.Prop1.Prop2.Prop3 то вобще тушите свет.
Короче для людей которые использовали нормальную лямбду очевидно что boost::lambda непригодно для реальной работы.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: BOOST, .NET, String.Split и производительность…
Здравствуйте, WolfHound, Вы писали:
WH>Вот скажи мне на сколько часто тебе нужны такая лямюбда? Мне нужно как минимум обратится к челену класса, а с этим уже все не так красиво... А если нужно както так Obj.Prop1.Prop2.Prop3 то вобще тушите свет. WH>Короче для людей которые использовали нормальную лямбду очевидно что boost::lambda непригодно для реальной работы.
Собственно говоря boost::lambda предназначен для того, чтобы не приходилось писать функции/функторы под простейшие случаи. Немогу не согласится, что для Obj.Prop1.Prop2.Prop3 это просто не пригодно. Вообщем более 'толстые' лямбды я все равно не пишу, предпочитаю функторы, т.к. это более декомпозиционно.
Re[13]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Курилка, Вы писали:
E>>>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.
К>>Т.е. ты декомпозицию делаешь при помощи ООП? При функциональной декомпозиции это будет выглядеть иначе, наследование там вообще как понятие не существует.
E>Не очень понимаю, о чем ты. Мне просто пару раз над элементами контейнеров пришлось делать несколько похожих, но отличающихся в деталях операций (каких именно уже не помню). Поэтому я сделал базовый класс, наследник от std::unary_function, в нем пару виртуальных методов. Затем пару производных классов, в которых эти виртуальные методы перекрывались. А потом в коде вызывал std::for_each то с одним наследником, то с другим.
О том, что если решать эту задачу с т.зр. ФП, то виртуальных методов не будет, а будет функция высшего порядка, в которую будут передаваться функции, которые соотвествуют твоим перекрытым методам.
Просто ты решал задачу в терминах объектов и тебе было так удобнее, кому-то возможно удобнее по-другому.
Re[7]: BOOST, .NET, String.Split и производительность…
Здравствуйте, McSeem2, Вы писали:
MS>Разница в том, что C# не вызывает ntdll по isspace (или какой там аналог?). А сишная библиотека от MS по кой-то фиг вызывает (ну или вызывала, не знаю как оно сейчас).
От МС? А что же тогда на Линусе 20 секунд в лучшем случае? Там тоже МС с ntdll накосявила?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: BOOST, .NET, String.Split и производительность…
Господа, ну ей богу как дети малые. Ну выводите вы в единых попугаях значения. Например в % от производительности на тестовой платформе самого первого приведенного исходника. Потому как понять, что быстрее — приведенный код на немерлях или написанный на коленке код на языке ЗЮ, если у меня нет немерле?
А то скучно за вашими писькомерянием наблюдать когда не видно у кого короче
ЗЫ: Все считать стёбом (Коим он собстна и является), кроме предложения "унифицировать" оценку производительности алгоритмов
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[11]: BOOST, .NET, String.Split и производительность…
Здравствуйте, vdimas, Вы писали:
V>>>Уже обсуждали. Бустовская лямбда хороша для мелких вещей по-месту. Для "крупных" нет проблем нарисовать 2 лишние строки для введения своего функтора: WH>>А Obj.Prop1.Prop2.Prop3 это крупный или мелкий случай?
V>для этого есть var().
V>
V>In sum, var(x) creates a nullary lambda functor, which stores a reference to the variable x. When the lambda functor is invoked, a reference to x is returned.
V>юзать так: V>
V>var(obj).Prop1.Prop2
V>
так юзать не получится
по сути var позволяет использовать переменные как лямда-выражение, но не наоборот.
V>Что характерно, так это вот такая особенность: V>
V>var(obj.Prop1).Prop2
V>
V>Понял, в чем прикол?
я не понял.
V>И кстати, lambda-выражения в этой либе можно делать многострочными, с сохранениями промежуточных результатов. Для этого есть еще пара хелперов: var_type и constant_type. (Я что-то не видел примеров здесь на RSDN, наверно мужики не в курсе )
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Что касается инфраструктуры, то в VW всё есть — и интеграция с CORBA, и облегченный протокол для ST-ST связи и уеб-сервисы. Думаю, что VA тоже не страдает отсутсвием инфраструктуры.
Кстати, все доки по VW тут. Изготовление "безголовых" приложений описано в DevGuide. Глава "Creating an Application without a GUI".
В главе "Refactoring" описаны доступные рефакторинги. Это просил Влад, а я забыл сразу ему ссылку кинуть. (Сейчас прочитает и начнёт опять меня в обмане уличать ). Там же было описание Rewrite Rules — "языка" для модификации кода, разработанного Беком в далёком 96гг вместе с RefactoringBrowser-ом, но сейчас я не могу его найти.
Здравствуйте, FR, Вы писали:
АХ>>А так напиши универсальный split и запости сюда результаты. FR>Вот такой не универсальный и наколенный вариант
Твой вариант работает не совсем правильно — попробуй два пробела подряд во входной строке написать.
Кроме того твой тест это чистой воды мухлеж. Если не пересоздавать, а очищать vector на кажой итерации, то бустовский вариант тоже ускорится раза в четыре.
Ниже более универсальный вариант. Вместо std::vector принимает любой контейнер с push_back, вместо строки принимает любой контейнер с последовательным константным итератором.
template <class C, class S, class P>
inline void split(C & c, const S & str, P & is_delimiter)
{
bool next_token = false;
typename S::const_iterator it = str.begin(), end = str.end(), token_start = it;
for(; it != end; ++it)
{
if (next_token)
{
next_token = false;
token_start = it;
}
if (is_delimiter(*it))
{
if (token_start != it)
c.push_back(S(token_start, it));
next_token = true;
}
}
if (!next_token && (token_start != it))
c.push_back(S(token_start, it));
}
Вот на таком тесте у меня этот вариант отрабатывает даже чуть быстрее твоего варианта(на нормальном тесте чуть медленнее, тестировалось на vc7.1 + dinkumware stl):
inline bool is_space(const char c)
{
return c == ' ';
}
int main()
{
int r = 0;
vector<string> tokens(5);
string str("123 345 asdf 23453 asdfas");
for(int i = 0; i < 1000000; ++i)
{
tokens.erase(tokens.begin(),tokens.end());
split(tokens, str, is_space);
r += tokens.size();
}
cout << r << endl;
return 0;
}
Здравствуйте, eao197, Вы писали:
E>Кстати, Андрей, вопрос в offtopic, а на Smalltalk не GUI-приложения вообще делают, server-side такой жесткий, черный ящик? Не web, про Seaside я знаю.
Чисто теоретически — никаких ограничений. Для VW идут сразу "безголовые" билды ВМ, то есть ВМ не умеющие работать с графикой. В доке описаны особенности изготовления безголовых приложений и особенности прикручивания к ним гуя назад.
Для Squeak есть опция командной строки, с которой он запускается в безоконном режиме. Хотя там, как я понимаю, фреймбуфер егойный инициализируется всё равно. Кстати, для администрирования удалённых Squeak приложений сделали имплементацию протокола VNC. Типа берёш обычный клиент, подключаешся и смотриш всё, что тебе нужно. Полноту реализиции протокола не знаю, но люди ним практически пользуются.
дык та же фигня, только в профиль.
var — это функция которая возвращает объект типа lambda_functor< identity<T&> > (var_type<T>::type это тайпдеф этого-же типа).
так-вот, в типе lambda_functor нет никаких переменных Prop1.
сделать то, что ты написал в си нельзя. даже макросами.
извращаются через бинд
Здравствуйте, Programmierer AG, Вы писали:
PA>FR wrote: >> Так что если очень хочется то и паттерн матчинг можно сделать PA>Очень забавный фокус, хотя это не паттерн матчинг. Да, похоже на guards, PA>но в паттерн матчинге важнее выбор пути исполнения в одновременно со PA>связыванием переменных, с разбором сложной структуры на части, а PA>этого в твоем примере ни разу нет.
Угу это скорее ближе к мультиметодам, но упрощает решение тех же задач что паттерн матчинг.
При желании можно и связывание переменных добавить.
А струкуры и сейчас вполне разбираются, аргументом может быть любой логический предикат, при его истиности вызывается связанная функция
@when("isinstance(x, basestring)")
def my_print(x):
print '<' + x + '>'
@when("isinstance(x, list)")
def my_print(x):
print "["
for i in x:
my_print(i)
print "]"
@when("True")
def my_print(x):
print x
PA><offtop> PA>А по каким словам надо гуглить, чтобы прочитать об этом трюке с @foobar? PA>Я тут для мелких скриптов начал Питон пробовать, но изучать некогда, PA>прыгать надо . PA></foobar>
Здравствуйте, FR, Вы писали:
FR>Я знаю (вернее уже почти забыл) как реализовано это в прологе(там вообще примитивно), это не так сложно как кажется. Вернее на порядки проще чем вывод типов. В общем вполне посильная задача.
Насколько мне извесно паттерн-матчинг в Эрналге встроенный и написан не на Эрланге.
FR>Но вообще я пока такую бибилотеку писать не собираюсь, оно хоть и реально, но очень трудоемко
Вот и я о том же. А результат будет скорее всего не очень хорошим.
FR>Не совсем, по моему ты переусложняешь.
Исходники я привел. Причем это резуальтат достигнут с использованием того самого паттерн-матчинга. Без него все будет намного более объемно и сложно.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, WolfHound, Вы писали:
V>>Уже обсуждали. Бустовская лямбда хороша для мелких вещей по-месту. Для "крупных" нет проблем нарисовать 2 лишние строки для введения своего функтора: WH>А Obj.Prop1.Prop2.Prop3 это крупный или мелкий случай?
для этого есть var().
In sum, var(x) creates a nullary lambda functor, which stores a reference to the variable x. When the lambda functor is invoked, a reference to x is returned.
юзать так:
var(obj).Prop1.Prop2
Что характерно, так это вот такая особенность:
var(obj.Prop1).Prop2
Понял, в чем прикол?
В общем, var явным образом определяет границы замыкания.
Как такое уточненное замыкание на C# сделать? Я не знаю (кроме как путем превращения мелкого однострочного случая в многострочный путем введения дополнительных "закрываемых" переменных).
А на Nemerle как это сделать элегантно?
-----------
Есть еще constant() для обратного: для насильного вычисления аргумента в момент создания замыкания.
И кстати, lambda-выражения в этой либе можно делать многострочными, с сохранениями промежуточных результатов. Для этого есть еще пара хелперов: var_type и constant_type. (Я что-то не видел примеров здесь на RSDN, наверно мужики не в курсе )
Понадобилось 'посплитить' строки (вообще задача более сложная, но обо всем по порядку), и по совету “мудрых старцев” (которые по новомодной традиции, при каждом чихе отправляют к boost-у) решил потестировать производительность boost::algoruthm:split.
Честно говоря, результаты меня обескуражили…
Код на C++, STL/BOOST:
int r = 0;
vector<string> tokens(5);
for(int i = 0; i < 1000000; i++)
{
split(tokens, "123 345 asdf 23453 asdfas", is_any_of(" "));
r += tokens.size();
}
Время работы: 20 секунд. (и это при полной оптимизации и отключенными проверками !?!)
Код на C#, .NET Framework:
int res = 0;
for(int i = 0; i < 1000000; i++)
res += "123 345 asdf 23453 asdfas".Split(' ').Length;
Console.WriteLine(res);
Время работы: ~1 сек, при 10^7 итераций ~6 сек.
Я уж тут подумал на кривизну рук, но пишу/писал на C++ достаточно долго, еще с первых GCC, TCPP 1.0, ..., и с оптимизаторами знаком не понаслышке.
[Есть подозрение на неграмотное дефолтовое аллокирование std::vector и std::string.]
Кстати .NET-ий JIT в Release-е особо не 'химичил' с этим кодом, и честно вызывал split для константной строки и далее inline-ил вызов get_Length() на возвращенном строковом массиве;
Пока переписал с исп. strtok и сделал запасной вариант под .NET.
Может есть что сказать приверженцам BOOST-а, и по возможности объяснить где "кривые руки"?
Re[3]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Здравствуйте, eao197, Вы писали:
E>>По моему беглому взгляду на реализацию split-а показалось, что дело в реализации is_any_of.
D>Даже если написать примитивный предикат:
D>bool char_is_space(const char c) D>{ D> return c == ' '; D>}
D>то заместо ~20 сек., получаем ~5 сек., на VC++ 8.0.
угу в бусте явно что-то перемудрили, даже вот такой кошмар:
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
int main(int argc, char *argv[])
{
int r = 0;
vector<string> tokens(5);
for(int i = 0; i < 1000000; i++)
{
istringstream istr("123 345 asdf 23453 asdfas");
string word;
int k = 0;
while(!istr.eof())
{
istr >> word;
tokens[k++] = word;
}
r += k;
}
cout << r << endl;
return 0;
}
работает в 8 раз быстрее чем бустовский вариант (vc71 + STLport-4.6)
Re[3]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
A>>Если взять STLPort, то результат будет лучше (циферки для AthlonXP@1916 MHz): A>>MSVC 2003: 20 сек A>>MSVC 2003 + STLPort 5.0: 6 сек.
A>>Если применить предикат, то время с STLPort сократиться до 2 сек.
D>Это все равно не очень радужный результат. У меня split-'велосипед' на STL-е с MSVC 2005 и strtok, выдает ~0.7 сек.
Очевидно что при многократном создании string получается медленне чем с strtok, который только указатели возвращает.
Могу подтвердить результат Aznog. У меня 2 сек. на MSVC 2005 + STLPort 5.1 + быстрый предикат типа isspace или bind2nd(equal_to<char>(),' ').
А если перейти на vector<iterator_range<string::iterator> >, то 1,2 сек.
Re[13]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Лисп и С++ создавались для несколько разных целей. D>Как говорил Деннис Ричи: "Одни языки создаются для решения задачи, другие для — доказания той или иной точки зрения".
А какое отношение Ричи и его миниатюрнинький язычек имеет к С++ и его монструозным порождениям вроде буста?
D>Лисп более относится к последней группы и писать на нем, мягко говоря по труднее чем на С++.
Ой, держите меня семеро. Я сейчас стану защитником Лиспа.
Ты меня извини, то на Лиспе писать то что есть в бусте в 100 раз проще. Язык банально создан для таких вещей. В метапрограммировании он один из лучших.
Как раз Лисп, по твоим словам "созданный для доказания той или иной точки зрения" прекрасно реализует идею "расширения языка за счет библиотек". А С++ тут выглядит очень убого.
D>Как ты предлагаешь исправлять их сегодня? Расширять язык или быть может чего убрать из него, что приведет к еще большей не совместимости, несмотря на то, что сейчас она уже просто чудовищная.
Элементарно, Ватсон (с). Добавить в язык то что люди безуспешно пытаются прикрутить к нему через одно место. Совместимость от этого не пострадает. К тому же можно ввести некие режимы. Например, в C# можно писать опасный код, но для этого нужно сказтаь об этом компилятору.
D>Я так понимаю ты плохо знаком со стандартом и хронологией его развития.
Да, да. Всегда проще найти проблему в оппоненте. Не признавать же свою неравоту?
D>Кстати стоит учитывать, что это сейчас при уже имеющемся опыте достаточно 3-х лет, но как говорится "всяк силен задним умом".
А что сейчас то изменеилось? Что опыт доступен только избранным? Что мешало проанализировать его 3, 6, 9 лет назад? Он же был. И он никуда не делся и сейчас. Стандарт 0x явно подразумевает что x — это римская 10. Так что время еще есть. Как раз можно успеть к 10-му году если начать работать уже сейчас.
D>Проблема у комитетчиков одна, не развалить до конца, чего и так шатается.
Мне кажется для языка опаснее оставлять все как есть.
D>Об этом много раз уже говорили. Язык сложен, противоречив и т.д. Не нравиться — не пиши, только зачем кричать об этом на каждом углу.
Не нравится. Не пишу. Уже давно. Лет 5 как...
VD>>Так что фанкторы — это самопальный костыль заменяющий то что требуется людям. А бусты — это попытка придать этому костылю приличный вид. Не очень удачная, надо сказать, попытка.
D>Слишком консервативное заявление, ведь многое зависит от размера/сложности функтора. Да и про декомпозицию не стоит забывать.
Ничего от размера не зависит. Достаточно месяцок пописать на языке с функциями высшего порядка и поймешь, что фанкторы это костыль. Причем неудобный.
D>Псевдокод: D>
D>если func — что-то типа выражения {a + _1}, то действительно функтор может быть избыточен.
Это еще одна ересь навиваемая С-шными корнями. В современных языках отказваются от указателей вообще. То как передавть объект или фунцию должен определять компилятор и/или рантайм. Если они умны, то без проблем могут вообще устранить сам факт передачи. Ведь код в конечном итоге не более чем инструкции процессора, то есть байты/биты.
D>Если уж так хочется, то напиши функцию которая будет инкапсулировать begin()/end().
А почему ее не написали в библиотеке? Да и как эту инкапсуляцию передавть в те самые функции STD и буста?
D>Есть задачи которые удобно писать под .NET, и на более простом языке типа C#. Особенно это важно в командных проектах.
Ага. Не спорю. Но какие задачи тебе удобно писать на С++? Не уж то ты драйверы пишешь?
D>Попробуй пописать на .NET под GBA (Game Boy Advance) или Nintendo DS, или его где нибудь где он просто не применим.
А ты для них пишешь?
И что С++ это единственный выбор для этих платформ?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD>Ты меня извини, то на Лиспе писать то что есть в бусте в 100 раз проще. Язык банально создан для таких вещей. В метапрограммировании он один из лучших. VD>Как раз Лисп, по твоим словам "созданный для доказания той или иной точки зрения" прекрасно реализует идею "расширения языка за счет библиотек". А С++ тут выглядит очень убого.
Неспорю, что макросы Лиспа позволяют это делать. Только вот синтаксис глаза режет, всмысле если это можно назвать синтаксисом. Я помню еще давно на отечественной персоналке "Вектор-06Ц" (проц. i8080) баловался с Форт-ом, тоже было интересное занятие, но я бы не стал его использовать в реальных, командных проектах, т.к. не каждый станет свое сознание переворачивать, для того чтобы писать на этом языке.
VD>Элементарно, Ватсон (с). Добавить в язык то что люди безуспешно пытаются прикрутить к нему через одно место. Совместимость от этого не пострадает. К тому же можно ввести некие режимы. Например, в C# можно писать опасный код, но для этого нужно сказтаь об этом компилятору.
Ох, не рассказывай про C# и опысный код (unsafe) . Обычно 'опасные' места пишу на C/C++ и интеропом добираюсь до этой функиональности.
VD>Да, да. Всегда проще найти проблему в оппоненте. Не признавать же свою неравоту?
Какая неправота? Да язык сложен, да в нем куча проблем, но комитет по крайней мере отсеил кучу дибильных предложений (которые существенно могли усугубить положение), которые предлагадись в свое время с неистовым интузиазмом. Почитай "Дизай и эволюция C++", на досуге, а то получается "чукча не читатель — чукча писатель".
VD>А что сейчас то изменеилось? Что опыт доступен только избранным? Что мешало проанализировать его 3, 6, 9 лет назад? Он же был. И он никуда не делся и сейчас. Стандарт 0x явно подразумевает что x — это римская 10. Так что время еще есть. Как раз можно успеть к 10-му году если начать работать уже сейчас.
К 0x никаких существенных изменений не произойдет, если не хотят растерять оставшихся 'пионеров' метапрограммирования.
VD>Мне кажется для языка опаснее оставлять все как есть.
Иногда лучшее действие — это бездействие.
VD>Ничего от размера не зависит. Достаточно месяцок пописать на языке с функциями высшего порядка и поймешь, что фанкторы это костыль. Причем неудобный. VD>Это еще одна ересь навиваемая С-шными корнями. В современных языках отказваются от указателей вообще. То как передавть объект или фунцию должен определять компилятор и/или рантайм. Если они умны, то без проблем могут вообще устранить сам факт передачи. Ведь код в конечном итоге не более чем инструкции процессора, то есть байты/биты.
Всё, извини, но дальнейшее обсуждение темы "функторы сакс" мне надоели.
D>>Если уж так хочется, то напиши функцию которая будет инкапсулировать begin()/end().
VD>А почему ее не написали в библиотеке?
Потому, что библиотека потенциалоьно рассчитана на нулевые издержки.
VD>Да и как эту инкапсуляцию передавть в те самые функции STD и буста?
Хоть тресни, но я не вижу неудобства в использовании итераторов.
VD>Ага. Не спорю. Но какие задачи тебе удобно писать на С++? Не уж то ты драйверы пишешь?
Драйвера, нет (хотя раньше бывало), а сейчас:
1). порой приходится писать для старых машинок.
2). важные с точти срезния производительности фрагменты (где .NET-кий аллокатор, ведет себя не лучшим образом).
D>>Попробуй пописать на .NET под GBA (Game Boy Advance) или Nintendo DS, или его где нибудь где он просто не применим. VD>А ты для них пишешь?
Да, немного.
VD>И что С++ это единственный выбор для этих платформ?
Asm, C/C++ (и представь себе STL).
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: BOOST, .NET, String.Split и производительность…
Здравствуйте, FR, Вы писали:
FR>кстати профайлер говорит что процентов 20 времени сидит в ntdll.dll на примерно таком коде:
[. . .]
FR>Похоже синхронизация неплохо отъедает производительность. Вообще в ntdll.dll сидит 49% времени в основном в строковых функциях и кусочках похожих тому что выше.
Во-во. Я тоже с этим сталкивался — isspace на винде отъедал больше половины всего времени работы парсера. Так что язык здесь ни при чем вообще.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[3]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Андрей Хропов, Вы писали:
АХ>Так все оптимизации выкручены по максимуму. Значение аргумента is_any_of известно во время компиляции. АХ>Все это должно заинлайниться до констант. Или этого не происходит, почему?
Судя по всему не происходит. Да и с чего бы происходить, если аргумент is_any_of неявно приводится к std::string (который может требовать у себя в конструкторе обращения к new), затем is_any_of возвращает какой-то объект, в котором еще что-то требует обращения к new, затем это еще к чему-то обращается и т.д. и т.п. Если есть желание, можешь сам расписать на бумаге цепочку вызовов внутри split-а, посмотри, в какие дебри это тебя заведет.
И вообще, я бы не стал надеятся на то, что компилятор умнее программиста и своими опримизирующими фокусами выправит кривизну рук разработчика.
АХ>P.S. Я смотрю у тебя Linux или BSD. Если не лень и стоят компиляторы других языков, то прогони проги из моего бенчмарка.
У меня WinXP + Cygwin. Да и лень
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Vermicious Knid, Вы писали:
VK>Здравствуйте, FR, Вы писали:
АХ>>>А так напиши универсальный split и запости сюда результаты. FR>>Вот такой не универсальный и наколенный вариант VK>Твой вариант работает не совсем правильно — попробуй два пробела подряд во входной строке написать.
Читай выше Все без гарантий
Хотя проверил, бустовский сплит работает также как мой, на два пробела выдает пустую строку, так что ошибка у тебя
VK>Кроме того твой тест это чистой воды мухлеж. Если не пересоздавать, а очищать vector на кажой итерации, то бустовский вариант тоже ускорится раза в четыре.
Где это там вектор пересоздается? Не было такого, у меня во всех вариантах vector<string> tokens(5); вынесен из цикла.
VK>Вот на таком тесте у меня этот вариант отрабатывает даже чуть быстрее твоего варианта(на нормальном тесте чуть медленнее, тестировалось на vc7.1 + dinkumware stl):
Угу у меня тоже.
Re[3]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
E>>По моему беглому взгляду на реализацию split-а показалось, что дело в реализации is_any_of.
D>Даже если написать примитивный предикат:
D>bool char_is_space(const char c) D>{ D> return c == ' '; D>}
D>то заместо ~20 сек., получаем ~5 сек., на VC++ 8.0.
Ну мужики, я ведь только заглянул в split и увидел большое количество копирований предиката. А дальше я не смотрел. Очень вероятно, что сам алгоритм поиска и выделения подстрок грешит таким же избыточным количеством копирований и передачи аргументов по значению.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Андрей Хропов, Вы писали:
АХ>Здравствуйте, Denis2005, Вы писали:
АХ>Обожаю бенчмарки :)
АХ>Померил с использованием таймеров (чтобы не учитывать JIT компиляцию) АХ>Вот результаты (усреднены по 10 запускам) АХ>(Athlon XP 1700+ @ 1.5 GHZ + 512Mb DDR266) АХ>:
АХ>1) DMD — 0.775 сек АХ>2) GDC — 0.905 сек АХ>3) С#/Nemerle — 1.1 сек АХ>4) Python — 3.48 сек АХ>5) Python+Psyco — 4.12 (не ускорил!) АХ>6) GCC + Boost — 22.5 сек АХ>7) MS VC++ + Boost — 35 сек
Вот еще одно подтверждение изначальной ущербности теста. Прошу сильно не пинать за код -- я очень долго ничего не писал на Haskell'е.
module Main where
import System.CPUTime (getCPUTime)
{- меня заленило лезть в документацию и искать функцию аналогичную split,
поэтому я реализовал её сам. -}
split :: (a -> Bool) -> [a] -> [[a]]
split _ [] = []
split p l = case break p l
of { (b, []) -> [b]
; ([], _) -> [[]]
; (b, (e:[])) -> [b]
; (b, (e:ex)) -> b : (split p ex)
}
fun :: Int -> Int
fun = fun' 0
where
fun' :: Int -> Int -> Int
fun' l n | n <= 0 = l
| otherwise
= fun'
{- следующая строка вычисляется только 1 раз,
в качестве первого аргумента функции fun'
всегда передается одно и тоже значение. -}
(l + (length (split (==' ') "123 345 asdf 23453 asdfas")))
(n - 1)
main :: IO ()
main = do { begin <- getCPUTime
; putStr "Res is "
; (putStr . show . fun) 1000000
; putStr ", "
; end <- getCPUTime
; (putStr . show) (((fromInteger (end - begin)) :: Double) / (1000000000 :: Double))
; putStrLn " ms. elapsed."
}
# ghc -O3 --make main.hs
# ./a.out
Res is 5000000, 8.998 ms. elapsed.
# ghc --version | head -n1
The Glorious Glasgow Haskell Compilation System, version 6.4.1
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, cattus, Вы писали:
C>>/* C>>Нет. Так сравнивать некорректно, потому что в других языках массивы могут быть C>>реализованы как деки (std::deque) или списки (std::list). std::vector всегда реалочится при увеличении размера, а, например, питоновские «массивы» на самом деле списки, C>>поэтому, операции конкатенации для них выполняются гааараздо быстрее. C>>Правильнее было бы использовать std::list. C>>*/
FR>Я вообще мерил с вынесенным за цикл вектором разница небольшая, так что дело не в этом.
C>># g++ test_with_list.cpp C>># ./a.out C>>res is 5000000,2673 ms elapsed
C>># g++ -O3 test_with_list.cpp C>># ./a.out C>>res is 5000000,653 ms elapsed
FR>странные у тебя какие то результаты, у меня с твоим кодом gcc3.2(mingw под WinXP) c -O3 дает res is/ 5000000,6063 ms elapsed FR>а gcc3.4.4(mingw под WinXP) c -O3 дает вообще res is/ 5000000,19985 ms elapsed FR>процессор Cel D 2.66
Все вопросы к реализации MinGW. И вообще, тестировать надо под нормальными операционками, а не под тормозами от дяди Билла. Попробуй другие компиляторы. Я собирал gcc-4.1.1 и gcc-3.3 - в обоих случаях результаты одинаковые, в первом случае линковалось с libstdc++.so.6, во втором - с libstdc++.so.5.
Цель то была доказать тезис о том, что С++ настолько крут, что в нем все можно сделать в бибилотеке... и лямбду, и замыкание, и черта лысого.
Насчет черта лысого не уверен, но лямбда удалась на славу:
void MyF1(vector<int>& vec, int s)
{
transform(vec.begin(), vec.end(), vec.begin(), (s + _1));
}
VC8.0 -O2
?MyF1@@YAXAAV?$vector@HV?$allocator@H@std@@@std@@H@Z PROC ; MyF1, COMDAT
mov eax, DWORD PTR _vec$[esp-4]
mov ecx, DWORD PTR [eax+4]
mov edx, DWORD PTR [eax+8]
mov eax, ecx
cmp eax, edx
push esi
push edi
je SHORT $LN71@MyF1
mov esi, DWORD PTR _s$[esp+4]
$LL82@MyF1:
mov edi, DWORD PTR [eax]
add edi, esi
mov DWORD PTR [ecx], edi
add eax, 4
add ecx, 4
cmp eax, edx
jne SHORT $LL82@MyF1
$LN71@MyF1:
pop edi
pop esi
ret 0
Очень похоже на нулевые издержки.
Re[13]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD>Он на Руби пишет, в лучшем случае. А там как и в С++ ООП основное средство декомпозиции. Других практически нет. Одними лямбдами (блоками) сыт не будешь.
Ага, а тебе еще паттерн-матчинг добавили. Он рулит покруче ООП и лямб вместе взятых.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[13]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>По поводу наследования: в своих OpenSource проектах с ходу не нашел. А код из закрытых проектов не смотрел, т.к. результат все равно не смогу показать. Но раз или два пришлось делать наследование для функторов, чтобы общую функциональность в базовый класс поместить. Ну и простейший пример наследования для функторов -- наследование от std::unary_function .
Автор маньякЪ!
Мне лень разбиратся но у меня такое чувство что ты гдето нетак провел декомпозицию.
У меня никогда не возникало жилания сделать такие функторы.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[14]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Был бы это не функтор, а свободная функция или метод, размер бы не сильно уменьшился,
Это зависит... от разрабочика. Разумный разработчик произвел бы декомпозицию функций и получил бы ряд более простых фунций и собераемую из инх более сложную функцию.
Кстати, это как раз тот случай когда как раз функции высшего порядка неимоверно "рулят". ООП обычно не дает детализировать алгоритмы, так как оверхэд на описание классов и их методов превышает выигрышь от самой декомпозиции.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
E>>Был бы это не функтор, а свободная функция или метод, размер бы не сильно уменьшился,
VD>Это зависит... от разрабочика. Разумный разработчик произвел бы декомпозицию функций и получил бы ряд более простых фунций и собераемую из инх более сложную функцию.
Ага, и программы у таких разработчиков работают, если в них ошибок нет.
Ты посмотри на код, там нет ничего сложного -- один цикл и несколько if-ов. Объем создает только форматирование и комментарии.
Но самое важное, что это только одна из простых функций, которые вместе реализуют довольно-таки сложный алгоритм. И мне было важно, чтобы на более высоком уровне я мог оперировать конструкциями типа std::for_each, std::find_if, std::transform и делать прозрачным более сложный код.
VD>Кстати, это как раз тот случай когда как раз функции высшего порядка неимоверно "рулят". ООП обычно не дает детализировать алгоритмы, так как оверхэд на описание классов и их методов превышает выигрышь от самой декомпозиции.
Ой-ой-ой. Не поверю.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[15]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD>Он не то чтобы по круче, но в купе с алгебраическими типами во многих случая получается куда как выразительнее, чем без них. В купе же я просто имею больше средств для выражения. Ведь я могу выбирать из довольно широкого списка: VD>1. ООП (причем отлично реализованный, модульный, компонентный...). VD>2. Функции высшего порядка (ФВП). VD>3. Макросы (тяжелая артилерия). VD>4. Алгебраические типы и паттерн-матчинг.
Можешь рассказать, какая помощь от макросов в обработке графовых структур?
VD>Причем последний пункт рельно по значемости я бы поставил на первое место. VD>Оно и не удивильно, что ты в случаях в кторых казалось бы классы на фиг не упали во всю их используешь да еще и "фанкторами" называешь. А меж тем Курилка прав. Подобные задачи без классов решаются только проще.
Нихрена они проще не получаются. Получаются те же продукты, только в профиль. Но об этом уже Cyberax сказал.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[6]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Odi$$ey, Вы писали:
MS>>Так что язык здесь ни при чем вообще.
OE> C# вроде как под той же виндой тестируют с той же самой ntdll.dll
Разница в том, что C# не вызывает ntdll по isspace (или какой там аналог?). А сишная библиотека от MS по кой-то фиг вызывает (ну или вызывала, не знаю как оно сейчас).
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[18]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>конструкциями типа std::for_each, std::find_if, std::transform и делать прозрачным более сложный код.
Это называется функции высшего порядка реализованные через зад автогеном.
VD>>Кстати, это как раз тот случай когда как раз функции высшего порядка неимоверно "рулят". ООП обычно не дает детализировать алгоритмы, так как оверхэд на описание классов и их методов превышает выигрышь от самой декомпозиции. E>Ой-ой-ой. Не поверю.
А зря. Только к проблеме нужно подходить комплексно.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Denis2005, Вы писали:
D>Компилятор: MS VC 8.0 D>Время работы: 20 секунд. (и это при полной оптимизации и отключенными проверками !?!)
D>Код на C#, .NET Framework: D>Время работы: ~1 сек, при 10^7 итераций ~6 сек.
FR wrote: > Так что если очень хочется то и паттерн матчинг можно сделать
Очень забавный фокус, хотя это не паттерн матчинг. Да, похоже на guards,
но в паттерн матчинге важнее выбор пути исполнения в одновременно со
связыванием переменных, с разбором сложной структуры на части, а
этого в твоем примере ни разу нет.
<offtop>
А по каким словам надо гуглить, чтобы прочитать об этом трюке с @foobar?
Я тут для мелких скриптов начал Питон пробовать, но изучать некогда,
прыгать надо .
</foobar>
Здравствуйте, eao197, Вы писали:
E>Да самый настоящий. Но это как бы дань моде. Интересно было еще про примеры узнать.
На счет не уеб-примеров — это всё таки "заказные" системы. Врядли о них много говорят. Хотя, к примеру, система, которую Бек разрабатывал для Крайслера в замен майнфреймовой системы в предверье миллениума (это с чего началось экстремальное программирование, afair). Сомневаюсь, что это было гуи-приложение. Система управления заводом по производству чипов — опять же, деталей нет но есть стойкое подозрение, что там есть и сервер-сайд компоненты.
Что касается инфраструктуры, то в VW всё есть — и интеграция с CORBA, и облегченный протокол для ST-ST связи и уеб-сервисы. Думаю, что VA тоже не страдает отсутсвием инфраструктуры.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, FR, Вы писали:
FR>>Там на самом деле частично виноват ms только не писатели операционки, а те кто писал рантайм к VC. Поэтому та же первоначальная версия теста откомпилированная со STLPort отрабатывает в полтора раза шустрее.
VD>Извини, а 1.5 раза и 30 раз проигрыша C#-e это сравненимые вещи? А под Линуксом что тормоизило?
Это уже проблемы бустовцев, как умудрились не знаю, мне некогда серъезно разбиратся.
Ну а проблема со строками в рантайме VC это уже вина ms, это тоже надо умудрится лазить без повода в ядро.
VD>А может это и правда заговор? Ну, МС специально подкупили всех писателей библиотек?
Они еще тестерам на линуксе мозги затуманивают так что нолик лишний пропадает
Re[3]: [Benchmark]:updated - Split на C++,D,C#,Nemerle,Boo,J
N>кстати, я правильно понимаю что D/C/C++ варианты оперирует с 8битными ASCII строками? ИМХО, скорее всего, именно это дает им определенное приемущество.
Проверял на C++ с wstring и L" никакой разницы по скорости.
При таком мелком размере строки я не удивился бы если бы с wstring было шустрее
Re[7]: [Benchmark]:updated - Split на C++,D,C#,Nemerle,Boo,J
Здравствуйте, n0name2, Вы писали:
N>Здравствуйте, VladD2, Вы писали:
VD>>На самом деле (с) GC жрет время не только во время сборки мусора, но и во время выделения памяти. Он рассчитан на работу в многопоточной среде и делает блокировки. Так что если сокнурент не делает блокировок или вообще использует стэк для хранения результатов, то скорость у него будет значительно выше. Но это в таких примитивных тестах. А в реальных условиях все компенсируется.
N>собственно, за счет TLA удалось улучшить время исполнения с ~500ms до ~400ms.
Исходников не вижу, так что и сказать ничего не могу. Но TLA (это видимо то что под Виндовс назвается LTS, т.е. локальное хранилище потока), тоже не беслатное. Оно значительно медленее стековой переменной. Так что на С всегда можено сделать чуточку быстрее.
Вот только кому это нужно. Код подобных оптимизаций неприлично большой. При этом выигрышь составляет проценты. Я тут где-то покзал, что даже испльзуя динамические списки выделяющие память на каждый элемент можно иметь приемлемую производительность и не иметь 30 ктратного отставания просто используя грамотно реализованные алгоритмы.
С++ в таких тестах перегнать практически невозможно, так как на нем всегда можно скатитсья в С-стиль с оптимизацией каждого бита. Вот только это неоправданно дорого и бессмысленно.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: BOOST, .NET, String.Split и производительность…
WH>Вот скажи мне на сколько часто тебе нужны такая лямюбда? Мне нужно как минимум обратится к челену класса, а с этим уже все не так красиво... А если нужно както так Obj.Prop1.Prop2.Prop3 то вобще тушите свет. WH>Короче для людей которые использовали нормальную лямбду очевидно что boost::lambda непригодно для реальной работы.
Уже обсуждали. Бустовская лямбда хороша для мелких вещей по-месту. Для "крупных" нет проблем нарисовать 2 лишние строки для введения своего функтора:
struct MyFunctor {}
и в нем
void operator()(arg&) {...}
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[14]: BOOST, .NET, String.Split и производительность…
Здравствуйте, WolfHound, Вы писали:
WH>Автор маньякЪ! WH>Мне лень разбиратся но у меня такое чувство что ты гдето нетак провел декомпозицию. WH>У меня никогда не возникало жилания сделать такие функторы.
Вообще-то нет. Посмотри, там действительно несколько вложенных if-ов. Имеет ли смысл их декомпозировать? У меня бывают участки подобного if-кода и подлиннее, особенно в той самой логике, котору почему-то называют "бизнес-". (когда позволяют типы аргументов, то это делается через switch-case, но суть не меняется).
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Доброго времени суток!
D>Понадобилось 'посплитить' строки (вообще задача более сложная, но обо всем по порядку), и по совету “мудрых старцев” (которые по новомодной традиции, при каждом чихе отправляют к boost-у) решил потестировать производительность boost::algoruthm:split.
D>Честно говоря, результаты меня обескуражили…
[skipped]
D>[Есть подозрение на неграмотное дефолтовое аллокирование std::vector и std::string.]
так и есть.
Столкнулся с такой же ситуацией, когда пререписывал анализатор логов написанный на perl на C++,
ожидалось, что программа на C++ будет работать быстрее, но perl функция split выигрывала в скорости в
десятки раз!
В итоге переписал с использованием strtok.
D>Может есть что сказать приверженцам BOOST-а, и по возможности объяснить где "кривые руки"?
ИМХО у разработчиков boost::algoruthm:split, если так хотелось STL интерфейс, то можно было
хотя бы std::list использовать вместо std::vector.
Re[2]: BOOST, .NET, String.Split и производительность…
Вообще говоря даже не компилируется.
Кстати .NET-ий имеет сигнатуру String.Split(params char[] separators), поэтому от тоже бежит по коллекции сепараторов.
Re[3]: BOOST, .NET, String.Split и производительность…
Denis2005 wrote: > Вообще говоря даже не компилируется. > Кстати .NET-ий имеет сигнатуру String.Split(params char[] separators), > поэтому от тоже бежит по коллекции сепараторов.
Тогда непонятно. В коде split'а при беглом просмотре нет ничего
криминального. Или баг, или какая-то странная фича (типа использования
локалей).
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[4]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Cyberax, Вы писали:
C>Denis2005 wrote: >> Вообще говоря даже не компилируется. >> Кстати .NET-ий имеет сигнатуру String.Split(params char[] separators), >> поэтому от тоже бежит по коллекции сепараторов. C>Тогда непонятно. В коде split'а при беглом просмотре нет ничего C>криминального. Или баг, или какая-то странная фича (типа использования C>локалей).
Врятли. Как я упоминал в первом сообщении подозрение на дуболомность дефолтовых аллокаторов у std::string и std::vector. У вас случаем не 'завалялось' какого-нибудь смарт-аллокатора для STL-контейнеров?
Re[2]: BOOST, .NET, String.Split и производительность…
A>ИМХО у разработчиков boost::algoruthm:split, если так хотелось STL интерфейс, то можно было A>хотя бы std::list использовать вместо std::vector.
Использование std::list не привело к повышению производительности. Более того, оно равно в данном случае, т.к. при конструировании задаётся размер контейнера.
Re[2]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
FR>>на питон переходи, вот такой код: FR>>
FR>>r = 0
FR>>for i in xrange(1000000):
FR>> r += len("123 345 asdf 23453 asdfas".split(" "))
FR>>print r
FR>>
FR>>отрабатывает за 2.5 секунды
D>Зачем мне питон, когда такой пример под .NET отрабатывает за 0.6 сек, и код даже короче (на C#_, чем в приведенном примере.
Ты там смайлик видел?
У меня шарп за полторы секунды отработал.
А код на шарпе длинее:
using System;
class MainApp
{
public static void Main()
{
int res = 0;
for(int i = 0; i < 1000000; i++)
res += "123 345 asdf 23453 asdfas".Split(' ').Length;
Console.WriteLine(res);
}
}
Re[3]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
FR>>отрабатывает за 2.5 секунды
D>Хоть напиши свой проц/память. У меня AMD Athlon 64 3000 (1.8), память DDR 667 Mhz. D>А то непонятно чего с чем меряем.
Cel D 2.6 память не знаю какая, но тормозная.
Re[3]: BOOST, .NET, String.Split и производительность…
Похоже синхронизация неплохо отъедает производительность. Вообще в ntdll.dll сидит 49% времени в основном в строковых функциях и кусочках похожих тому что выше.
Re[2]: BOOST, .NET, String.Split и производительность…
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, Denis2005, Вы писали:
D>>Я уж тут подумал на кривизну рук, но пишу/писал на C++ достаточно долго, еще с первых GCC, TCPP 1.0, ..., и с оптимизаторами знаком не понаслышке. D>>[Есть подозрение на неграмотное дефолтовое аллокирование std::vector и std::string.]
FR>Вряд ли тут аллокаторы помогут. Тут просто сами строки неправильные. Попробуй поискать реализации const_string наверно будет шустрее.
Даже если сделать такой неправельный const_string (заглушка, чисто для теста):
Здравствуйте, Андрей Хропов, Вы писали:
АХ>6) GCC + Boost — 22.5 сек АХ>7) MS VC++ + Boost — 35 сек
А добавьте ка пунктик C++ + самописный split
Бо что то мне кажется что тут надо в "консерватории" что то подправить
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, Андрей Хропов, Вы писали:
АХ>5) Python+Psyco — 4.12 (не ускорил!)
Psyco не любит когда код в основном теле модуля надо его в функцию засунуть, тогда чуть ускорит:
from time import clock
import psyco
psyco.full()
def run():
res = 0
for i in xrange(1000000):
res += len("123 345 asdf 23453 asdfas".split(" "))
return res
start = clock()
res = run()
finish = clock()
print 'res is %s, %f sec elapsed' % ( res, finish - start )
У меня python 2.4.1 ~ 2.6 сек.
python 2.4.1 + psyco 1.5.0 ~ 1.8 сек.
IronPython-1.0 ~ 3.0 сек.
Здравствуйте, CreatorCray, Вы писали:
CC>Здравствуйте, Андрей Хропов, Вы писали:
АХ>>6) GCC + Boost — 22.5 сек АХ>>7) MS VC++ + Boost — 35 сек CC>А добавьте ка пунктик C++ + самописный split CC>Бо что то мне кажется что тут надо в "консерватории" что то подправить
Здравствуйте, FR, Вы писали:
CC>>А добавьте ка пунктик C++ + самописный split CC>>Бо что то мне кажется что тут надо в "консерватории" что то подправить FR>лучше держи на очень не шустром интерпретаторе:
не, сравнение агоритма boost с алгоримом встроенным в интерпретатор меня не очень то интересует. Больше все таки интересует насколько хреново реализовали split в самом бусте.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Есть такой, итеративно strtok-ом собирает в vector<string> с заранее заданной размерностью.
По результатам производительность чуть ниже .NET-кого варианта.
Вообщем в BOOST-е, чего-то бравые парни перемудрили,
и нулевыми издержками в данном случае совсем не попахивает.
Надеюсь в C++0x это безобразие полностью не попадет,
или если попадет, то в более продуманном варианте.
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, Андрей Хропов, Вы писали:
АХ>>5) Python+Psyco — 4.12 (не ускорил!)
FR>Psyco не любит когда код в основном теле модуля надо его в функцию засунуть, тогда чуть ускорит:
Ммм, да, почесав затылок, вспомнил что он вроде пофункционально оптимизирует.
И у меня теперь ускорил даже совсем не чуть а почти в 2 раза
Теперь обновленная таблица с твоим вариантом выглядит как:
Интересно, а что будет если использовать внутри цикла в C++ вариант python через boost.python .
Поможет ли это реанимировать boost (в смысле будет ли быстрее чем 35 сек)?
Здравствуйте, CreatorCray, Вы писали:
CC>Здравствуйте, Андрей Хропов, Вы писали:
АХ>>6) GCC + Boost — 22.5 сек АХ>>7) MS VC++ + Boost — 35 сек CC>А добавьте ка пунктик C++ + самописный split CC>Бо что то мне кажется что тут надо в "консерватории" что то подправить
Странно почему boost себя так плохо показывает.
Его вроде далеко не новички пишут, да и peer review у них вроде есть.
Надо идти к ним на форум ругаться
А то прям стыд и срам какой-то.
А так напиши универсальный split и запости сюда результаты.
Re[2]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Denis2005, Вы писали:
D>>Честно говоря, результаты меня обескуражили…
D>>Время работы: 20 секунд. (и это при полной оптимизации и отключенными проверками !?!) D>>Может есть что сказать приверженцам BOOST-а, и по возможности объяснить где "кривые руки"?
E>По моему беглому взгляду на реализацию split-а показалось, что дело в реализации is_any_of. В частности, в том, что при каждом обращении к split объект-предикат, который скрывается за is_any_of конструируется заново. И более того, где-то там внутри этот предикат передается в подчиненные функции и сохраняется во вспомогательных объектах по значению.
Так все оптимизации выкручены по максимуму. Значение аргумента is_any_of известно во время компиляции.
Все это должно заинлайниться до констант. Или этого не происходит, почему?
P.S. Я смотрю у тебя Linux или BSD. Если не лень и стоят компиляторы других языков, то прогони проги из моего бенчмарка.
Наблюдаются ли те же временные пропорции?
Здравствуйте, Андрей Хропов, Вы писали:
CC>>А добавьте ка пунктик C++ + самописный split CC>>Бо что то мне кажется что тут надо в "консерватории" что то подправить АХ>Странно почему boost себя так плохо показывает.
Это у них бывает. Похоже народ о производительности не очень то задумывается... АХ>А так напиши универсальный split и запости сюда результаты.
Появится время и острая потребность — займусь
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[6]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD>Естественно. Причем библиотеки.
VD>Только вот когда любители С++ начинают пенесометрией по скорости заниматься они как-то забывают, что в программе многое от библиотек зависит и все время приводят вручную оптимизированный код.
Дык библиотеки то в первую очередь надо оптимизировать. К примеру большую часть CRT можно (и нужно) переписывать с нуля с учетом производительности. Потому как тормозная она...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[3]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
E>>А любителям boost-ов я бы напомнил: KISS
VD>Ты прочти свое сообщение и подумай кому бы еще о KISS напомнить.
И кому?
Если хочешь позлословить по поводу приведенного мной кода, то это всего лишь популярное изложение части деталей реализации boost::algorithms::is_any_of. К реализации которого я не имею никакого отношения.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: BOOST, .NET, String.Split и производительность…
АХ>Интересно, а что будет если использовать внутри цикла в C++ вариант python через boost.python . АХ>Поможет ли это реанимировать boost (в смысле будет ли быстрее чем 35 сек)?
Мерять надо, в принципе накладные расходы на вызов (python — C++) относительно небольшие (у меня миллион вызовов примерно секунда), так что скорее всего будет быстрее
Re[2]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Denis2005, Вы писали:
D>>Честно говоря, результаты меня обескуражили…
D>>Время работы: 20 секунд. (и это при полной оптимизации и отключенными проверками !?!) D>>Может есть что сказать приверженцам BOOST-а, и по возможности объяснить где "кривые руки"?
E>По моему беглому взгляду на реализацию split-а показалось, что дело в реализации is_any_of. В частности, в том, что при каждом обращении к split объект-предикат, который скрывается за is_any_of конструируется заново. И более того, где-то там внутри этот предикат передается в подчиненные функции и сохраняется во вспомогательных объектах по значению.
Попробовал с самописным предикатом:
#include <iostream>
#include <vector>
#include <boost/algorithm/string/split.hpp>
using namespace std;
using boost::algorithm::split;
inline bool is_space(char c)
{
return c == ' ';
}
int main(int argc, char *argv[])
{
int r = 0;
vector<string> tokens(5);
for(int i = 0; i < 1000000; i++)
{
split(tokens, "123 345 asdf 23453 asdfas", is_space);
r += tokens.size();
}
return 0;
}
результаты(первый с boost::algorithm::is_any_of)
vc71 | 33.2 и 9.7
vc71 + STLport-4.6 | 24.9 и 9.9
gcc3.2 | 10.8 и 3.5
gcc догнал скрипты
Re[2]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Андрей Хропов, Вы писали:
АХ>Странно почему boost себя так плохо показывает. АХ>Его вроде далеко не новички пишут, да и peer review у них вроде есть. АХ>Надо идти к ним на форум ругаться АХ>А то прям стыд и срам какой-то.
АХ>А так напиши универсальный split и запости сюда результаты.
Вот такой не универсальный и наколенный вариант
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void split(vector<string> &out, const char *text, bool (*pred)(char))
{
out.erase(out.begin(), out.end());
const char *begin_word = text;
for(; *text; ++text)
{
const char c = *text;
if(pred(c))
{
out.push_back(string(begin_word, text - begin_word));
begin_word = text + 1;
}
}
if(text != begin_word)
out.push_back(string(begin_word, text - begin_word));
}
inline bool is_space(char c)
{
return c == ' ';
}
int main(int argc, char *argv[])
{
int r = 0;
vector<string> tokens(5);
for(int i = 0; i < 1000000; i++)
{
split(tokens, "123 345 asdf 23453 asdfas", is_space);
r += tokens.size();
}
cout << r << endl;
/*for(int i = 0; i < tokens.size(); ++i)
{
cout << tokens[i] << endl;
}*/return 0;
}
уже не оставляет шансов бусту(почти в 30 раз для vc8). Вообще надо разобратся как они умудрились такое тормозное сделать.
Здравствуйте, FR, Вы писали:
FR>Хотя проверил, бустовский сплит работает также как мой, на два пробела выдает пустую строку, так что ошибка у тебя
Да, ты прав. Просто в случае пробелов это как-то нелогично. Но если разделители запятые или что-то вроде того, то тогда действительно это имеет смысл.
Но раз уж так задумано, то тогда все еще проще, и еще слегка быстрее:
template <class C, class S, class P>
inline void split(C & c, const S & str, P & is_delimiter)
{
typename S::const_iterator it = str.begin(), token_start = it, end = str.end();
for(; it != end; ++it)
{
if (is_delimiter(*it))
{
if (token_start != it)
c.push_back(S(token_start, it));
++(token_start = it);
}
}
if (token_start != it)
c.push_back(S(token_start, it));
}
FR>Где это там вектор пересоздается? Не было такого, у меня во всех вариантах vector<string> tokens(5); вынесен из цикла.
В твоих примерах нет. Но в примерах на C# и других языках массивы то создаются заново на каждом вызове. Поэтому я согласен с Андреем Хроповым, что так корректнее сравнивать.
Re[7]: BOOST, .NET, String.Split и производительность…
Здравствуйте, CreatorCray, Вы писали:
CC>Дык библиотеки то в первую очередь надо оптимизировать. К примеру большую часть CRT можно (и нужно) переписывать с нуля с учетом производительности. Потому как тормозная она...
А это кому-то надо?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
VD>>Ты прочти свое сообщение и подумай кому бы еще о KISS напомнить.
E>И кому?
Да действительно, кому?
E>Если хочешь позлословить по поводу приведенного мной кода, то это всего лишь популярное изложение части деталей реализации boost::algorithms::is_any_of. К реализации которого я не имею никакого отношения.
Что там "злословить" то? Проблема выеденного яйца не стоит. А ты тут целый трактат написал. Так что KISS.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, CreatorCray, Вы писали:
CC>>Дык библиотеки то в первую очередь надо оптимизировать. К примеру большую часть CRT можно (и нужно) переписывать с нуля с учетом производительности. Потому как тормозная она...
VD>А это кому-то надо?
Иногда надо.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
FR>>Где это там вектор пересоздается? Не было такого, у меня во всех вариантах vector<string> tokens(5); вынесен из цикла.
VK>В твоих примерах нет. Но в примерах на C# и других языках массивы то создаются заново на каждом вызове. Поэтому я согласен с Андреем Хроповым, что так корректнее сравнивать.
При тех тромозах что показал бустовский сплит не принципиально
Да и добавить нормальный аллокатор вектору и строкам (хотя бы тот же boost::pool) и не будет разницы где разместить.
Re: BOOST, .NET, String.Split и производительность…
A>Если взять STLPort, то результат будет лучше (циферки для AthlonXP@1916 MHz): A>MSVC 2003: 20 сек A>MSVC 2003 + STLPort 5.0: 6 сек.
A>Если применить предикат, то время с STLPort сократиться до 2 сек.
Это все равно не очень радужный результат. У меня split-'велосипед' на STL-е с MSVC 2005 и strtok, выдает ~0.7 сек.
Причем пришлось отказаться от std::string. Конечно, не очень хороший код во многих смыслах
(в частности коверкает исх. строку и раставляет указатели на полученные 'обрывки' str),
но свою задачу решает за приемлемое время.
P.S. Меня больше интересует куда исчезает принцип нулевых издержек из рекомендуемых библиотек C++?
Re[9]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Андрей Хропов, Вы писали:
АХ>Здравствуйте, Denis2005, Вы писали:
АХ>Обожаю бенчмарки :)
АХ>Померил с использованием таймеров (чтобы не учитывать JIT компиляцию) АХ>Вот результаты (усреднены по 10 запускам) АХ>(Athlon XP 1700+ @ 1.5 GHZ + 512Mb DDR266) АХ>:
АХ>4) Python — 3.48 сек АХ>6) GCC + Boost — 22.5 сек
АХ>С++:
АХ>
АХ>#include <vector>
АХ>#include <string>
АХ>#include <iostream>
АХ>#include <boost/algorithm/string/split.hpp>
АХ>#include <boost/algorithm/string/classification.hpp>
АХ>#include <windows.h> // for GetTickCount
АХ>using namespace std;
АХ>using namespace boost::algorithm;
АХ>int main()
АХ>{
АХ> DWORD start = GetTickCount();
АХ> int res = 0;
АХ> for(int i = 0; i < 1000000; i++)
АХ> {
АХ> // так корректней сравнивать, ведь в др программах мы размер не указывали
АХ> // + по моим тестам почти не повлияло на скорость/*
Нет. Так сравнивать некорректно, потому что в других языках массивы могут быть
реализованы как деки (std::deque) или списки (std::list). std::vector всегда реалочится при увеличении размера, а, например, питоновские «массивы» на самом деле списки,
поэтому, операции конкатенации для них выполняются гааараздо быстрее.
Правильнее было бы использовать std::list.
*/
АХ> vector<string> tokens;
//
АХ> split(tokens, "123 345 asdf 23453 asdfas", is_any_of(" "));
АХ> res += tokens.size();
АХ> }
АХ> DWORD stop = GetTickCount();
АХ> cout << "res is " << res << ',' << stop - start << " ms elapsed\n";
АХ> return 0;
АХ>}
АХ>
Мой вариант:
#include <list>
#include <string>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#define OS_POSIX
#ifdef OS_WINDOWS
#include <windows.h> // for GetTickCount#else// posix#include <sys/times.h>
#endif
using namespace std;
using namespace boost::algorithm;
int main()
{
#ifdef OS_WINDOWS
DWORD start = GetTickCount();
#else
struct tms t;
clock_t start = times(&t);
#endif
int res = 0;
for(int i = 0; i < 1000000; i++)
{
list<string> tokens;
split(tokens, "123 345 asdf 23453 asdfas", is_any_of(" "));
res += tokens.size();
}
#ifdef OS_WINDOWS
DWORD stop = GetTickCount();
#else
clock_t stop = times(&t);
#endif
cout << "res is/ " << res << ',' << stop - start << " ms elapsed\n";
return 0;
}
# g++ test_with_vector.cpp
# ./a.out
res is/ 5000000,3117 ms elapsed
# g++ -O3 test_with_vector.cpp
# ./a.out
res is/ 5000000,756 ms elapsed
# g++ test_with_deque.cpp
# ./a.out
res is 5000000,2919 ms elapsed
# g++ -O3 test_with_deque.cpp
# ./a.out
res is 5000000,801 ms elapsed
# g++ test_with_list.cpp
# ./a.out
res is 5000000,2673 ms elapsed
# g++ -O3 test_with_list.cpp
# ./a.out
res is 5000000,653 ms elapsed
# python test.py
res is 5000000, 2.100000 sec elapsed
# cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 15
model : 3
model name : Intel(R) Pentium(R) 4 CPU 2.80GHz
stepping : 4
cpu MHz : 2794.054
cache size : 1024 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 1
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 5
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe pni monitor ds_cpl cid xtpr
bogomips : 5589.58
processor : 1
vendor_id : GenuineIntel
cpu family : 15
model : 3
model name : Intel(R) Pentium(R) 4 CPU 2.80GHz
stepping : 4
cpu MHz : 2794.054
cache size : 1024 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 1
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 5
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe pni monitor ds_cpl cid xtpr
bogomips : 5585.27
Здравствуйте, cattus, Вы писали:
C>/* C>Нет. Так сравнивать некорректно, потому что в других языках массивы могут быть C>реализованы как деки (std::deque) или списки (std::list). std::vector всегда реалочится при увеличении размера, а, например, питоновские «массивы» на самом деле списки, C>поэтому, операции конкатенации для них выполняются гааараздо быстрее. C>Правильнее было бы использовать std::list. C>*/
Я вообще мерил с вынесенным за цикл вектором разница небольшая, так что дело не в этом.
C># g++ test_with_list.cpp C># ./a.out C>res is 5000000,2673 ms elapsed
C># g++ -O3 test_with_list.cpp C># ./a.out C>res is 5000000,653 ms elapsed
странные у тебя какие то результаты, у меня с твоим кодом gcc3.2(mingw под WinXP) c -O3 дает res is/ 5000000,6063 ms elapsed
а gcc3.4.4(mingw под WinXP) c -O3 дает вообще res is/ 5000000,19985 ms elapsed
процессор Cel D 2.66
fun :: Int -> Int
fun = fun' 0
where
fun' :: Int -> Int -> Int
fun' l n | n <= 0 = l
| otherwise
= fun'
(l +
{- следующая строка вычисляется только 1 раз,
в качестве первого аргумента функции fun'
всегда передается одно и тоже значение. -}
(length (split (==' ') "123 345 asdf 23453 asdfas")))
(n - 1)
C>Все вопросы к реализации MinGW. И вообще, тестировать надо под нормальными операционками, а не под тормозами от дяди Билла. Попробуй другие компиляторы. Я собирал gcc-4.1.1 и gcc-3.3 - в обоих случаях результаты одинаковые, в первом случае линковалось с libstdc++.so.6, во втором - с libstdc++.so.5.
Другие еще сильнее тормозят
А буст у тебя какой версии?
Вообще не верится что от стандартной библиотеки так зависит, я пробовал с boost::pool_allocator не помогло.
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, cattus, Вы писали:
C>>Все вопросы к реализации MinGW. И вообще, тестировать надо под нормальными операционками, а не под тормозами от дяди Билла. Попробуй другие компиляторы. Я собирал gcc-4.1.1 и gcc-3.3 - в обоих случаях результаты одинаковые, в первом случае линковалось с libstdc++.so.6, во втором - с libstdc++.so.5.
FR>Другие еще сильнее тормозят FR>А буст у тебя какой версии? FR>Вообще не верится что от стандартной библиотеки так зависит, я пробовал с boost::pool_allocator не помогло.
Здравствуйте, cattus, Вы писали:
C>Поигравши с лисповыми макрами, мой друг улучьшил время выполнения кода до 0 мс, притом время выполнения совершенно не зависит от N. ))
надо полагать сырцы тока завтра будут..?
Re[4]: BOOST, .NET, String.Split и производительность…
) который работает с теми же string и создает их на каждый чих, получается гораздо шустрее чем с boost::algorithm::split?
Да и скрипты и шарп и D тоже создают строки и обгоняют буст без проблем.
S>Могу подтвердить результат Aznog. У меня 2 сек. на MSVC 2005 + STLPort 5.1 + быстрый предикат типа isspace или bind2nd(equal_to<char>(),' '). S>А если перейти на vector<iterator_range<string::iterator> >, то 1,2 сек.
А на vc71 + STLport-4.6 с быстрым предикатом STLPort совсем не ускоряет.
Здравствуйте, _rasta, Вы писали:
C>>Поигравши с лисповыми макрами, мой друг улучьшил время выполнения кода до 0 мс, притом время выполнения совершенно не зависит от N. ))
_>надо полагать сырцы тока завтра будут..?
Здравствуйте, VladD2, Вы писали:
C>>Все вопросы к реализации MinGW. И вообще, тестировать надо под нормальными операционками, а не под тормозами от дяди Билла. VD>Ну, вот мы и выяснили в чем проблема С++. Проблема как всегда в деде Билле. Если бы не он, то буст был бы в 30 раз быстрее и удобнее. Я всегда знал что это ЗАГОВОР!
ну вот зачем писать бред?
изначально было: 6) GCC + Boost — 22.5 сек
7) MS VC++ + Boost — 35 сек
время GCC + Boost было достаточно тривиально улучшено до 6063(653) ms, по разным данным, что как минимум 4 (40) раз быстрее. буста у меня, к сожалению, нет, но можно попросить присутствующих собрать представленый код в лялихе с указанными либами и выложить время выполнения. если время будет не сильно отличаться от заявленного cattus-ом, то таки да, вянда традиционно г-но. все же просто...
Здравствуйте, Odi$$ey, Вы писали:
OE>>>ничего, что также изначально было OE>>>C# (под той же виндой) — 1сек ? _>>но с этим-то никто не спорил OE>ну дык если под одной и той же виндой результат зависит от языка/библиотек с какой радости может быть "таки да, вянда традиционно г-но"?
я там смайлик забыл
собсно упор делался на то, чтов лялихе же быстрее работает, пока никто не сказал обратного
Здравствуйте, _rasta, Вы писали:
_>Здравствуйте, Odi$$ey, Вы писали:
OE>>>>ничего, что также изначально было OE>>>>C# (под той же виндой) — 1сек ? _>>>но с этим-то никто не спорил OE>>ну дык если под одной и той же виндой результат зависит от языка/библиотек с какой радости может быть "таки да, вянда традиционно г-но"?
_>я там смайлик забыл _>собсно упор делался на то, чтов лялихе же быстрее работает, пока никто не сказал обратного
Это пока неподвержденные данные, жаль не смогу скоро добратся до linux'а с установленным бустом.
C># g++ test_with_vector.cpp C># ./a.out C>res is/ 5000000,3117 ms elapsed
C># g++ -O3 test_with_vector.cpp C># ./a.out C>res is/ 5000000,756 ms elapsed
C># g++ test_with_deque.cpp C># ./a.out C>res is 5000000,2919 ms elapsed
C># g++ -O3 test_with_deque.cpp C># ./a.out C>res is 5000000,801 ms elapsed
C># g++ test_with_list.cpp C># ./a.out C>res is 5000000,2673 ms elapsed
C># g++ -O3 test_with_list.cpp C># ./a.out C>res is 5000000,653 ms elapsed
C># python test.py C>res is 5000000, 2.100000 sec elapsed
Перед всеми извиняюсь, ляпнул.
#include <list>
#include <string>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#define OS_POSIX
#ifdef OS_WINDOWS
#include <windows.h> // for GetTickCount#else// posix#include <sys/times.h>
#endif
using namespace std;
using namespace boost::algorithm;
int main()
{
#ifdef OS_WINDOWS
DWORD start = GetTickCount();
#else
struct tms t;
long ts = sysconf(_SC_CLK_TCK);
double start = ((double) times(&t) / ts) * 1000;
#endif
int res = 0;
for(int i = 0; i < 1000000; i++)
{
list<string> tokens;
split(tokens, "123 345 asdf 23453 asdfas", is_any_of(" "));
res += tokens.size();
}
#ifdef OS_WINDOWS
DWORD stop = GetTickCount();
#else
double stop = ((double) times(&t) / ts) * 1000;
#endif
cout << "res is " << res << ',' << stop - start << " ms elapsed\n";
return 0;
}
Так как функция sysconf(_SC_CLK_TCK) (количество тиков в секунду) на моей машине возвращает 100, достаточно каждый из вышеприведённых результатов умножить на 10.
C># g++ test_with_vector.cpp C># ./a.out C>res is/ 5000000,31170 ms elapsed
C># g++ -O3 test_with_vector.cpp C># ./a.out C>res is/ 5000000,7560 ms elapsed
C># g++ test_with_deque.cpp C># ./a.out C>res is 5000000,29190 ms elapsed
C># g++ -O3 test_with_deque.cpp C># ./a.out C>res is 5000000,8010 ms elapsed
C># g++ test_with_list.cpp C># ./a.out C>res is 5000000,26730 ms elapsed
C># g++ -O3 test_with_list.cpp C># ./a.out C>res is 5000000,6530 ms elapsed
То есть лучший результат 6,530 сек.
Re[9]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Собственно говоря boost::lambda предназначен для того, чтобы не приходилось писать функции/функторы под простейшие случаи. Немогу не согласится, что для Obj.Prop1.Prop2.Prop3 это просто не пригодно. Вообщем более 'толстые' лямбды я все равно не пишу, предпочитаю функторы, т.к. это более декомпозиционно.
Что только люди не приюдумают для того чтобы оправдать использование С++.
По сравнению с нормальной лямбдой функторы не рулят совершенно.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[10]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.
Код в студию.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[11]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, WolfHound, Вы писали:
WH>>По сравнению с нормальной лямбдой функторы не рулят совершенно.
E>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.
Т.е. ты декомпозицию делаешь при помощи ООП? При функциональной декомпозиции это будет выглядеть иначе, наследование там вообще как понятие не существует.
Re[12]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Курилка, Вы писали:
E>>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.
К>Т.е. ты декомпозицию делаешь при помощи ООП? При функциональной декомпозиции это будет выглядеть иначе, наследование там вообще как понятие не существует.
Не очень понимаю, о чем ты. Мне просто пару раз над элементами контейнеров пришлось делать несколько похожих, но отличающихся в деталях операций (каких именно уже не помню). Поэтому я сделал базовый класс, наследник от std::unary_function, в нем пару виртуальных методов. Затем пару производных классов, в которых эти виртуальные методы перекрывались. А потом в коде вызывал std::for_each то с одним наследником, то с другим.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[14]: BOOST, .NET, String.Split и производительность…
Курилка wrote: > О том, что если решать эту задачу с т.зр. ФП, то виртуальных методов не > будет, а будет функция высшего порядка, в которую будут передаваться > функции, которые соотвествуют твоим перекрытым методам.
То же самое, вид сбоку.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[15]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Cyberax, Вы писали:
C>Курилка wrote: >> О том, что если решать эту задачу с т.зр. ФП, то виртуальных методов не >> будет, а будет функция высшего порядка, в которую будут передаваться >> функции, которые соотвествуют твоим перекрытым методам. C>То же самое, вид сбоку.
Не спорю, просто кому-то удобней может быть такой вид, а кому-то наоборот
Здравствуйте, Denis2005, Вы писали:
D>Насчет черта лысого не уверен, но лямбда удалась на славу:
D>
D>void MyF1(vector<int>& vec, int s)
D>{
D> transform(vec.begin(), vec.end(), vec.begin(), (s + _1));
D>}
D>
Да, уж на славу... для тех кто нормальной не видел. _1 уже круто. А возьми случаи чуть по сложнее и ты приплыл. Ведь лямбды хороши тем, что это фукнции высшего порядка которые можно комбинировать.
Да и проблем с ними не оберешся. В языках где они реализовны нормально, они имеют лексическую область видимости и их время жизни оеределяется наличием ссылок на них. Тут же фиг. А на дисерт пиколы вроде ничаянного добавления переменной с именем _1 в локальную область видимости, невнятные сообщения об ошибках и т.п.
Кстати, даже в такх, примитивных, случаях языки с полноценной поддержкой функций высшего порядка выглядят лучше.
Вот как это будет выглядить не Немерле:
transform.(s + _);
"s + _" автоматом преобразуется в лямбду с одним параметром (никаких лишних скобок и хардкодед-имен вроде "_1" не нужно). Да и отсуствие идиотизма с begin()/end() разгружает код. В итоге получается, что писать функционально конечно на С++ можно, но неудобно, не всегда быстро, и очень громоздко.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Собственно говоря boost::lambda предназначен для того, чтобы не приходилось писать функции/функторы под простейшие случаи. Немогу не согласится, что для Obj.Prop1.Prop2.Prop3 это просто не пригодно. Вообщем более 'толстые' лямбды я все равно не пишу, предпочитаю функторы, т.к. это более декомпозиционно.
Для тех кто плотно попользовался функцями высшего порядка (ФВП), лямбды и локальные фукнции становятся частью средств декомпозиции кода и они начинают применяться повсеместно. Не важно насколько сложен случай. Уж обращаться к членам классов точно постоянно нужно (особенно в императивном С++).
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.
А что классы в других языках отменили что ли? Просто в других языках нет нужны эмулировать классами функции высшего порядка. Они уже есть в языке шататно.
И тебе ли это не знать? Снова поспорить охота?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Курилка, Вы писали:
К>Т.е. ты декомпозицию делаешь при помощи ООП? При функциональной декомпозиции это будет выглядеть иначе, наследование там вообще как понятие не существует.
Он на Руби пишет, в лучшем случае. А там как и в С++ ООП основное средство декомпозиции. Других практически нет. Одними лямбдами (блоками) сыт не будешь.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: BOOST, .NET, String.Split и производительность…
Здравствуйте, FR, Вы писали:
E>>Кстати, вопрос к тем, кто смайлики ставит: а что смешного?
FR>размер
Был бы это не функтор, а свободная функция или метод, размер бы не сильно уменьшился, а вот читабельность могла пострадать. Поскольку в случае функции цикл перебора коллекции пришлось бы размещать у нее внутри (там и так есть большой цикл), и все эти проверки были бы внутри цикла, либо их бы пришлось вынести в отдельную функцию, которая бы получала сонмище аргументов. Так что хрен редьки не слаще.
К тому же для реальной (а не форумной пенисометрии) задачи объем получился весьма удовлетворительный: декларация функтора, тело operator() и тело вспомогательного метода, поотдельности занимают не более одной странички A4.
Так что это real life, смешного, как обычно, не много.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[8]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Denis2005, Вы писали:
D>>Насчет черта лысого не уверен, но лямбда удалась на славу:
D>>
D>>void MyF1(vector<int>& vec, int s)
D>>{
D>> transform(vec.begin(), vec.end(), vec.begin(), (s + _1));
D>>}
D>>
VD>Да, уж на славу... для тех кто нормальной не видел. _1 уже круто. А возьми случаи чуть по сложнее и ты приплыл. Ведь лямбды хороши тем, что это фукнции высшего порядка которые можно комбинировать.
Они хороши только тем, что не потребовали расширения и без того очень 'широкого' языка.
Случаи чуть по сложнее решаются обычно функторами.
VD>Да и проблем с ними не оберешся. В языках где они реализовны нормально, они имеют лексическую область видимости и их время жизни оеределяется наличием ссылок на них. Тут же фиг. А на дисерт пиколы вроде ничаянного добавления переменной с именем _1 в локальную область видимости, невнятные сообщения об ошибках и т.п.
Невнятные сообщения об ошибках, это вполне нормальный случай, если библиотекой решается, то на, что изначально язык не был ориентирован.
VD>Кстати, даже в такх, примитивных, случаях языки с полноценной поддержкой функций высшего порядка выглядят лучше. VD>Вот как это будет выглядить не Немерле: VD>
VD>transform.(s + _);
VD>
VD>"s + _" автоматом преобразуется в лямбду с одним параметром (никаких лишних скобок и хардкодед-имен вроде "_1" не нужно). Да и отсуствие идиотизма с begin()/end() разгружает код. В итоге получается, что писать функционально конечно на С++ можно, но неудобно, не всегда быстро, и очень громоздко.
Без лишних скобок: transform(vec.begin(), vec.end(), vec.begin(), s + _1);
А вот насчет begin()/end() не понял. Чем итераторы то не угодили?
Re[14]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
VD>>Он на Руби пишет, в лучшем случае. А там как и в С++ ООП основное средство декомпозиции. Других практически нет. Одними лямбдами (блоками) сыт не будешь.
E>Ага, а тебе еще паттерн-матчинг добавили. Он рулит покруче ООП и лямб вместе взятых.
Он не то чтобы по круче, но в купе с алгебраическими типами во многих случая получается куда как выразительнее, чем без них. В купе же я просто имею больше средств для выражения. Ведь я могу выбирать из довольно широкого списка:
1. ООП (причем отлично реализованный, модульный, компонентный...).
2. Функции высшего порядка (ФВП).
3. Макросы (тяжелая артилерия).
4. Алгебраические типы и паттерн-матчинг.
Причем последний пункт рельно по значемости я бы поставил на первое место.
Оно и не удивильно, что ты в случаях в кторых казалось бы классы на фиг не упали во всю их используешь да еще и "фанкторами" называешь. А меж тем Курилка прав. Подобные задачи без классов решаются только проще.
В общем-то я тут согласен с Гапертоном — классы больше подходят для общего дизайна прилоежния. Для реализации ФВП и другие прибмабасы лучше подходят.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Они хороши только тем, что не потребовали расширения и без того очень 'широкого' языка.
Что широкого в этом языке? Почему его нельзя целенаправлено рсширить действительно общепризнанно удобными возможностями? Зачем их эмулировать на коленке?
Хотя... мне уже по фигу. Меня этот вопрос занимал несколько лет назад. Теперь моя позиция очень простая. Горбатого могила исправит. Пусть гниет дальше.
D>Случаи чуть по сложнее решаются обычно функторами.
"Обычными"? Это где они слали обычными? Что-то я такого чуда природы в языках с функциями высшего прядка вообще не видел. И знаешь, мне кажется, что это потому, что фанкторы на фиг не упали.
D>Невнятные сообщения об ошибках, это вполне нормальный случай,
Серьезно? Дочего можно довести себя самовнушением?!
D>если библиотекой решается, то на, что изначально язык не был ориентирован.
А зачем тогда делать это в библиотеке? Почему не расширить язык тем что многим так нужно? Ведь получится элегантнее, быстрее (код быстрее будет), удобнее и с нормальной диагностикой ошибок. Какова цель згонять популярный язык в угол?
D>Без лишних скобок: transform(vec.begin(), vec.end(), vec.begin(), s + _1); D>А вот насчет begin()/end() не понял. Чем итераторы то не угодили?
А зачем они нужны? В функциональных языках все обходятся одновсязанным списком, который так и называется "список".
Если в коде присуствует vec.begin() и vec.end() — это уже избыточный код. Ведь работа ведется со всем списком и отдельно указывать его голову так же глупо как на вопрос о расстоянии до объекта начинать давать его координаты и координаты место где ты находишся.
В общем, С++, точнее его создатели, нарушили один очень важный принцип KISS. И это его погубит. А пока он не умер, можно извлечь пользу для сбея и своей конторы перейдя на более продуктивный язык и набляюдая как туча ежиков колются, плачут но продолжают с упоением жрать это кактус.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD>Что широкого в этом языке? Почему его нельзя целенаправлено рсширить действительно общепризнанно удобными возможностями? Зачем их эмулировать на коленке?
VD>А зачем тогда делать это в библиотеке? Почему не расширить язык тем что многим так нужно? Ведь получится элегантнее, быстрее (код быстрее будет), удобнее и с нормальной диагностикой ошибок. Какова цель згонять популярный язык в угол?
Понять жизнь можно лишь оглядываясь назад, но жить-то приходится, смотря вперед. (C) Сёрен Кьеркегор
Была избрана такая политика, чтобы помаксимому давить на библиотеки, т.к. язык и без того слишком сложный и многими местами противоричивый.
Ты же знаешь, сколько времени нужно WG21 X3J16 чтобы принят то или иное решение, особенно если оно касается расширений.
А сколько пройдет когда реальными компиляторами будет поддерживаться введеное расширение?
Вот с библиотекой дела обстоят немного попроще, поэтому на них и делается основной упор.
VD>Хотя... мне уже по фигу. Меня этот вопрос занимал несколько лет назад. Теперь моя позиция очень простая. Горбатого могила исправит. Пусть гниет дальше.
'Горбатый' еще задаст жару молодым неокрепшим умам
D>>Случаи чуть по сложнее решаются обычно функторами.
VD>"Обычными"? Это где они слали обычными? Что-то я такого чуда природы в языках с функциями высшего прядка вообще не видел. И знаешь, мне кажется, что это потому, что фанкторы на фиг не упали.
Я сказал обычно, и применительно для C++. В C# 2.0 нормально обхожусь анонимными делегатами.
VD>А зачем они нужны? В функциональных языках все обходятся одновсязанным списком, который так и называется "список". VD>Если в коде присуствует vec.begin() и vec.end() — это уже избыточный код. Ведь работа ведется со всем списком и отдельно указывать его голову так же глупо как на вопрос о расстоянии до объекта начинать давать его координаты и координаты место где ты находишся.
За всех говорит не стоит. Частенько бывает, что работа ведется с определенными фрагментами коллекции.
Хотя там где производительность особо не важна, можно и полными списками погонять.
VD>В общем, С++, точнее его создатели, нарушили один очень важный принцип KISS. И это его погубит. А пока он не умер, можно извлечь пользу для сбея и своей конторы перейдя на более продуктивный язык и набляюдая как туча ежиков колются, плачут но продолжают с упоением жрать это кактус.
Сам пишу пот .NET уже > 4 лет, если задача позволяет, поэтому про ежиков заканчивай.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[19]: BOOST, .NET, String.Split и производительность…
Здравствуйте, WolfHound, Вы писали:
E>>конструкциями типа std::for_each, std::find_if, std::transform и делать прозрачным более сложный код. WH>Это называется функции высшего порядка реализованные через зад автогеном.
Мне по барабану, как они называются вообще, а для моего конкретного случая это означало бы, что я не мог бы вызывать внутри алгоритма лямбды на 30-ть строк длиной, а передавал бы в аналог for_each функцию. И вызов:
std::find_if( c.begin(), c.end(), functor )
не сильно отличается от
c.find_if &functor
поскольку тело functor-а и его инициализация определены где-то в другом месте.
VD>>>Кстати, это как раз тот случай когда как раз функции высшего порядка неимоверно "рулят". ООП обычно не дает детализировать алгоритмы, так как оверхэд на описание классов и их методов превышает выигрышь от самой декомпозиции. E>>Ой-ой-ой. Не поверю. WH>А зря. Только к проблеме нужно подходить комплексно.
Так подходите. Вы же даже не знаете задачи, частью которой является приведенный мной код, а ухмыляться себе позволяете. В форумах на словах все мастера.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, FR, Вы писали:
FR>Угу это скорее ближе к мультиметодам, но упрощает решение тех же задач что паттерн матчинг. FR>При желании можно и связывание переменных добавить. FR>А струкуры и сейчас вполне разбираются, аргументом может быть любой логический предикат, при его истиности вызывается связанная функция
Предикат — это не то. Что я буду тебе рассказывать, ты ведь с Хаскелем игрался. Как такое на Питоне изобразить (объединение множеств из стандартной библиотеки Окамла):
let rec union s1 s2 =
match (s1, s2) with
(Empty, t2) -> t2
| (t1, Empty) -> t1
| (Node(l1, v1, r1, h1), Node(l2, v2, r2, h2)) ->
if h1 >= h2 then
if h2 = 1 then add v2 s1 else begin
let (l2, _, r2) = split v1 s2 in
join (union l1 l2) v1 (union r1 r2)
end
else
if h1 = 1 then add v1 s2 else begin
let (l1, _, r1) = split v2 s1 in
join (union l1 l2) v2 (union r1 r2)
end
Здравствуйте, Programmierer AG, Вы писали:
PA>Здравствуйте, FR, Вы писали:
FR>>Угу это скорее ближе к мультиметодам, но упрощает решение тех же задач что паттерн матчинг. FR>>При желании можно и связывание переменных добавить. FR>>А струкуры и сейчас вполне разбираются, аргументом может быть любой логический предикат, при его истиности вызывается связанная функция PA>Предикат — это не то. Что я буду тебе рассказывать, ты ведь с Хаскелем игрался. Как такое на Питоне изобразить (объединение множеств из стандартной библиотеки Окамла):
Просто структуры данных питона очень плохо приспособленны для сопоставления с образцом. Но в принципе решаемо вводом новых типов, с которыми сможет работать сопоставление (аналог variant из nemerle) и плюс адаптеров к встроенным спискам, туплам и т. п. Но это слишком трудоемко Поэтому мне пока более интересно возится с аналогами мультиметодов, они с одной стороны слабее pattern matching'а c другой наооборот мощнее.
Здравствуйте, Denis2005, Вы писали:
D>Понять жизнь можно лишь оглядываясь назад, но жить-то приходится, смотря вперед. (C) Сёрен Кьеркегор
Не тот случай. Как раз С++ делает то, что давно (очень, 30 лет назад) было сделано в других языках. В частности в Лиспе.
D>Была избрана такая политика, чтобы помаксимому давить на библиотеки, т.к. язык и без того слишком сложный и многими местами противоричивый.
Язык особой сложностью не обладает. Даже C# имеет более сложный синтаксис и порой более сложную семантику. А вот противоричивость — это да. Что есть того не отнять. Только это даеко не плюс. Это огромный минус. Именно это, и то что язык пытаются расширять не штатнными средствами и приводит к повышению сложности языка. Причем совершенно не поравданной сложности, заметь.
D>Ты же знаешь, сколько времени нужно WG21 X3J16 чтобы принят то или иное решение, особенно если оно касается расширений.
И чьи это проблемы? Это проблемы тех кто сделал ужасный стандарт в 1993-ем и не хотят исправлять своих ошибок сегодня.
D>А сколько пройдет когда реальными компиляторами будет поддерживаться введеное расширение?
Опять же это проблемы дизайна языка. Противоричивость и кривизна его дизайна усложняют компиляторщикам жизнь. Отсюда и задержки. Хотя с последнего стандарта прошло 13 лет. За это время черта лсого можно было сделать. Так что факт недареализованности стандарта основными компиляторами скорее говорит об избыточности и непродуманности стандарта.
Учитывая то что 3 года достаточно для разработки языка с нуля, проблемы С++-ных комитетчиков вообще выглядят очень странно.
D>Вот с библиотекой дела обстоят немного попроще, поэтому на них и делается основной упор.
В библиотеках как мы видим все очень печально. Они просто не могут прыгнуть выше головы. С++ не обладает штатными средствами расширения (за исключением убогих макросов), что приводит к использованию неполноценных нештатных средств. Результат при этом получается удручающий. Ужасное время на компиляцию. Невозможность реализации задуманного на 100%. Ужасно сложная отладка. Никакие сообщения об ошибках. И в добавок огромнеший геморрой при попытках сделать код совместимым с компиляторами разных производителей. В общем, я бы оценил это положение дел как ужасающее.
D>'Горбатый' еще задаст жару молодым неокрепшим умам
Он уже никому ничего не задаст. Он давно перешел в разряд битомолотилки с избыточным синтаксисом. Не удивлюсь если через 10 лет С буедет иметь большую популяроность чем С++.
Сегодняшняя же популярность обуславливается только двумя факторами охринительной разрекламмированностью и человеческими привычками. Они еще долго будут держать С++ в фаворитакх. Вот только проивзодительность руда программистов на этом языке крайне низка. Особенно если речь вести о высококлассных специалистах. И использовать его себе могут позволить только очень богатые конторы (вроде МС и Сана, ну, на худой конец как-нить наш СиБосс и то он себе вубыток работает). Маленькая же контора используя С++ надевает на себя огромный гандикап.
VD>>"Обычными"? Это где они слали обычными? Что-то я такого чуда природы в языках с функциями высшего прядка вообще не видел. И знаешь, мне кажется, что это потому, что фанкторы на фиг не упали.
D>Я сказал обычно, и применительно для C++. В C# 2.0 нормально обхожусь анонимными делегатами.
Вот вот. А C# 2.0 анонимные методы чудовищьно неудобны. Вот в C# 3.0 другое дело.
Так что фанкторы — это самопальный костыль заменяющий то что требуется людям. А бусты — это попытка придать этому костылю приличный вид. Не очень удачная, надо сказать, попытка.
VD>>А зачем они нужны? В функциональных языках все обходятся одновсязанным списком, который так и называется "список". VD>>Если в коде присуствует vec.begin() и vec.end() — это уже избыточный код. Ведь работа ведется со всем списком и отдельно указывать его голову так же глупо как на вопрос о расстоянии до объекта начинать давать его координаты и координаты место где ты находишся.
D>За всех говорит не стоит. Частенько бывает, что работа ведется с определенными фрагментами коллекции.
Что значит за всех? Это банальный логический вывод. Если в коде есть vec.begin() и vec.end() одновременно, то это точно перебор всего списка. А раз так, то это явно избыточный код, так как в нем достаточно было бы указать просто "vec".
D>Хотя там где производительность особо не важна, можно и полными списками погонять.
Извини, но твои рассуждения о производительности звучат очень несерьезно. Производительность определяется в первую очередь качеством алогоритмов, и как показла эта тема библиотек (по сути их алгоритмов). И как видишь используя бусты можно спокойно не догадываясь об этом получить низко-эффективный код на казалось бы "таком быстром языке".
В функциональных языках работа со списками является чуть ли не основой возможностью и там давно пришли к выводу, что опереровать нужно понятием "список", а не "открезок". Если есть списко в котором лежат лишние элементы, то сначал проще отфильровать нужные элеметы, а потом уже обработать новый списко. Эффективность от этого нисколько не пострадает.
VD>>В общем, С++, точнее его создатели, нарушили один очень важный принцип KISS. И это его погубит. А пока он не умер, можно извлечь пользу для сбея и своей конторы перейдя на более продуктивный язык и набляюдая как туча ежиков колются, плачут но продолжают с упоением жрать это кактус.
D> D>Сам пишу пот .NET уже > 4 лет, если задача позволяет, поэтому про ежиков заканчивай.
А что же так? Писали бы на С++. С ним ведь все так здорово!
И ведь донет с C# далеко не лидеры в области выразительности. Сравнение с ним С++ хотя и вглядит тормозом разрабоки, но все же еще как-то смотрится. А вот по сравнению с новыми гибридами вроде Скалы и Немерла он выглядит как недоразумение. Хотя и по сравнению с функциональными языками прошлого вроде Лиспа или ОКамла он тоже выглядит не очень здорово.
Что до "задача позволяет", то лично у меня вообще нет задач которые бы не позволяли использовать дотнет. Думаю, что большинство людей просто недооценивает его (и Явы) возможности.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, FR, Вы писали:
FR>А струкуры и сейчас вполне разбираются, аргументом может быть любой логический предикат, при его истиности вызывается связанная функция
Ты не понял. Паттерн не всегда являюется придикатом. Даже скажу больше. Хороший паттерн всегд не предикат. Паттерн это описание структуры данных с возможносью задать метапеременные (то есть части этой структуры выразить как wildcards).
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, FR, Вы писали:
FR>Просто структуры данных питона очень плохо приспособленны для сопоставления с образцом.
Не "просто", это одна из проблем. Почему ты думаешь при разговоре о паттерн-матчинге все время всплывают алгеброические типы данных (варинаты)? Именно потому, что они сделаны так чтобы по ним можно было делать сложный паттерн-матчинг. Но их наличие это еще не все. Еще нужен ээ... думатель (как точно подметил Ц-Смаил). Этот думатель должен преобразовать паттерн в набор логических предикатов. Это нехилый алгоритм. В Немерле его тупо скомуниздили из одной из реализаций ML-я. Его уже так на коленке не напишишь. Да и в рантайме его отрабатывать слишком накладно.
FR>Но в принципе решаемо вводом новых типов, с которыми сможет работать сопоставление (аналог variant из nemerle) и плюс адаптеров к встроенным спискам, туплам и т. п. Но это слишком трудоемко Поэтому мне пока более интересно возится с аналогами мультиметодов, они с одной стороны слабее pattern matching'а c другой наооборот мощнее.
В принципе все решаемо. Только это будет уже не Питон, а Гюрза или еще что-то. И решать конечно такие вещи лучше на уровне компилятора, а не на уровне интепретируемого в рантайме метапрограммирования.
Пойми, паттерн-матчинг только выглядит просто. А внтри это довольно высокотезнологичные алгоритмы.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>В главе "Refactoring" описаны доступные рефакторинги. Это просил Влад, а я забыл сразу ему ссылку кинуть. (Сейчас прочитает и начнёт опять меня в обмане уличать ).
О! Не прошло и года. Списибо!
Тогда сразу вопрос. Возьмем к примеру:
Renaming a Method and its References To rename all implementors of a method, all senders, and all symbols
references, select Rename... from the Method menu.
In addition to strict renaming, this refactoring operation also enables you
to rearrange the method’s parameters. However, when rearranging the
parameters, any symbols that are performed cannot be permuted.
Правильно ли я понял эти строки, что можно переименовывать только все методы с одинаковым мменем во всех классах одновременно? Или все же можно изменить имя метода в одном классе и оставить без изменений другие методы с тем же именем и списком параметров?
Предполжим у мея есть кассы A и B. В обоих содержатся метод MyMethod. Можно ли переименовать метод в классе A на MyMethodEx не трокая метода из класса B и соотвественно корретно исправить все ссылки на переименованный метод.
Если это возможно, то второй вопрос. Как среда отделяет вызовы методов в случае когда например, объект передается в качестве параметра и не ясно что за тип будет у этого объекта?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD>Не тот случай. Как раз С++ делает то, что давно (очень, 30 лет назад) было сделано в других языках. В частности в Лиспе.
Лисп и С++ создавались для несколько разных целей.
Как говорил Деннис Ричи: "Одни языки создаются для решения задачи, другие для — доказания той или иной точки зрения".
Лисп более относится к последней группы и писать на нем, мягко говоря по труднее чем на С++.
D>>Ты же знаешь, сколько времени нужно WG21 X3J16 чтобы принят то или иное решение, особенно если оно касается расширений. VD>И чьи это проблемы? Это проблемы тех кто сделал ужасный стандарт в 1993-ем и не хотят исправлять своих ошибок сегодня.
Как ты предлагаешь исправлять их сегодня? Расширять язык или быть может чего убрать из него, что приведет к еще большей не совместимости, несмотря на то, что сейчас она уже просто чудовищная.
VD>Учитывая то что 3 года достаточно для разработки языка с нуля, проблемы С++-ных комитетчиков вообще выглядят очень странно.
Я так понимаю ты плохо знаком со стандартом и хронологией его развития.
Кстати стоит учитывать, что это сейчас при уже имеющемся опыте достаточно 3-х лет, но как говорится "всяк силен задним умом".
Проблема у комитетчиков одна, не развалить до конца, чего и так шатается.
VD>В библиотеках как мы видим все очень печально. Они просто не могут прыгнуть выше головы. С++ не обладает штатными средствами расширения (за исключением убогих макросов), что приводит к использованию неполноценных нештатных средств. Результат при этом получается удручающий. Ужасное время на компиляцию. Невозможность реализации задуманного на 100%. Ужасно сложная отладка. Никакие сообщения об ошибках. И в добавок огромнеший геморрой при попытках сделать код совместимым с компиляторами разных производителей. В общем, я бы оценил это положение дел как ужасающее.
Об этом много раз уже говорили. Язык сложен, противоречив и т.д. Не нравиться — не пиши, только зачем кричать об этом на каждом углу.
VD>Он уже никому ничего не задаст. Он давно перешел в разряд битомолотилки с избыточным синтаксисом. Не удивлюсь если через 10 лет С буедет иметь большую популяроность чем С++.
VD>Сегодняшняя же популярность обуславливается только двумя факторами охринительной разрекламмированностью и человеческими привычками. Они еще долго будут держать С++ в фаворитакх. Вот только проивзодительность руда программистов на этом языке крайне низка. Особенно если речь вести о высококлассных специалистах. И использовать его себе могут позволить только очень богатые конторы (вроде МС и Сана, ну, на худой конец как-нить наш СиБосс и то он себе вубыток работает). Маленькая же контора используя С++ надевает на себя огромный гандикап.
VD>Вот вот. А C# 2.0 анонимные методы чудовищьно неудобны. Вот в C# 3.0 другое дело.
VD>Так что фанкторы — это самопальный костыль заменяющий то что требуется людям. А бусты — это попытка придать этому костылю приличный вид. Не очень удачная, надо сказать, попытка.
Слишком консервативное заявление, ведь многое зависит от размера/сложности функтора. Да и про декомпозицию не стоит забывать.
если func — что-то типа выражения {a + _1}, то действительно функтор может быть избыточен.
D>>За всех говорит не стоит. Частенько бывает, что работа ведется с определенными фрагментами коллекции. VD>Что значит за всех? Это банальный логический вывод. Если в коде есть vec.begin() и vec.end() одновременно, то это точно перебор всего списка. А раз так, то это явно избыточный код, так как в нем достаточно было бы указать просто "vec".
Если уж так хочется, то напиши функцию которая будет инкапсулировать begin()/end().
VD>А что же так? Писали бы на С++. С ним ведь все так здорово! VD>И ведь донет с C# далеко не лидеры в области выразительности. Сравнение с ним С++ хотя и вглядит тормозом разрабоки, но все же еще как-то смотрится. А вот по сравнению с новыми гибридами вроде Скалы и Немерла он выглядит как недоразумение. Хотя и по сравнению с функциональными языками прошлого вроде Лиспа или ОКамла он тоже выглядит не очень здорово.
Есть задачи которые удобно писать под .NET, и на более простом языке типа C#. Особенно это важно в командных проектах.
VD>Что до "задача позволяет", то лично у меня вообще нет задач которые бы не позволяли использовать дотнет. Думаю, что большинство людей просто недооценивает его (и Явы) возможности.
Попробуй пописать на .NET под GBA (Game Boy Advance) или Nintendo DS, или его где нибудь где он просто не применим.
Mono — не предлагать, по любому ресурсов у обозначенных выше аппаратов не хватит.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[8]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
MS>>Разница в том, что C# не вызывает ntdll по isspace (или какой там аналог?). А сишная библиотека от MS по кой-то фиг вызывает (ну или вызывала, не знаю как оно сейчас).
VD>От МС? А что же тогда на Линусе 20 секунд в лучшем случае? Там тоже МС с ntdll накосявила?
Влад, ты слова читать умеешь? Напомню, что в моем сообщении речь шла о неком другом случае, а не о split. На Линухе он не проверялся.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[9]: BOOST, .NET, String.Split и производительность…
Здравствуйте, McSeem2, Вы писали:
MS>Влад, ты слова читать умеешь? Напомню, что в моем сообщении речь шла о неком другом случае, а не о split. На Линухе он не проверялся.
О како таком другом случае? Я просто уже второй раз тут вижу, что проблемы в МС. Очень интересна эта теория. Люблю, знаете ли, теорию заговора.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, FR, Вы писали:
FR>>А струкуры и сейчас вполне разбираются, аргументом может быть любой логический предикат, при его истиности вызывается связанная функция
VD>Ты не понял. Паттерн не всегда являюется придикатом. Даже скажу больше. Хороший паттерн всегд не предикат. Паттерн это описание структуры данных с возможносью задать метапеременные (то есть части этой структуры выразить как wildcards).
Я знаю, пролог изучал правда давно и недавно игрался с языками с паттерн матчингом. Да и не зря я смайлик поставил
Вообще это скорее пример использования скажем так условных мультиметодов
А эта вещь только соприкасается с сопоставлением с образцом, хотя тоже вещь мощная.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, FR, Вы писали:
FR>>Просто структуры данных питона очень плохо приспособленны для сопоставления с образцом.
VD>Не "просто", это одна из проблем. Почему ты думаешь при разговоре о паттерн-матчинге все время всплывают алгеброические типы данных (варинаты)? Именно потому, что они сделаны так чтобы по ним можно было делать сложный паттерн-матчинг. Но их наличие это еще не все. Еще нужен ээ... думатель (как точно подметил Ц-Смаил). Этот думатель должен преобразовать паттерн в набор логических предикатов. Это нехилый алгоритм. В Немерле его тупо скомуниздили из одной из реализаций ML-я. Его уже так на коленке не напишишь. Да и в рантайме его отрабатывать слишком накладно.
Я знаю (вернее уже почти забыл) как реализовано это в прологе(там вообще примитивно), это не так сложно как кажется. Вернее на порядки проще чем вывод типов. В общем вполне посильная задача.
FR>>Но в принципе решаемо вводом новых типов, с которыми сможет работать сопоставление (аналог variant из nemerle) и плюс адаптеров к встроенным спискам, туплам и т. п. Но это слишком трудоемко Поэтому мне пока более интересно возится с аналогами мультиметодов, они с одной стороны слабее pattern matching'а c другой наооборот мощнее.
VD>В принципе все решаемо. Только это будет уже не Питон, а Гюрза или еще что-то. И решать конечно такие вещи лучше на уровне компилятора, а не на уровне интепретируемого в рантайме метапрограммирования.
Ну эрланг вполне справляется, и в питоне в случае тормозов можно и на си кое что переписать.
Но вообще я пока такую бибилотеку писать не собираюсь, оно хоть и реально, но очень трудоемко
Меня пока устраивают и маленькие трюки типа этого "pattern matching".
VD>Пойми, паттерн-матчинг только выглядит просто. А внтри это довольно высокотезнологичные алгоритмы.
Не совсем, по моему ты переусложняешь.
Re[2]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD> Особенноп риятно этот тест сравнивать с вот этоим произведением человеческой мысли .
Пардон. Забыл ссылку дать. Вот этот код мне больше всего понравился. Истенно в духе С++, т.е. пол лохунгом "зато быстро!". Re: Наколенный вариант 8-летней давности
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, McSeem2, Вы писали:
MS>>Влад, ты слова читать умеешь? Напомню, что в моем сообщении речь шла о неком другом случае, а не о split. На Линухе он не проверялся.
VD>О како таком другом случае? Я просто уже второй раз тут вижу, что проблемы в МС. Очень интересна эта теория. Люблю, знаете ли, теорию заговора.
Там на самом деле частично виноват ms только не писатели операционки, а те кто писал рантайм к VC. Поэтому та же первоначальная версия теста откомпилированная со STLPort отрабатывает в полтора раза шустрее.
Re[11]: BOOST, .NET, String.Split и производительность…
Здравствуйте, FR, Вы писали:
FR>Там на самом деле частично виноват ms только не писатели операционки, а те кто писал рантайм к VC. Поэтому та же первоначальная версия теста откомпилированная со STLPort отрабатывает в полтора раза шустрее.
Извини, а 1.5 раза и 30 раз проигрыша C#-e это сравненимые вещи? А под Линуксом что тормоизило?
А может это и правда заговор? Ну, МС специально подкупили всех писателей библиотек?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: BOOST, .NET, String.Split и производительность…
Здравствуйте, McSeem2, Вы писали:
MS>Если бы ты был чуть более внимательным, то заметил бы, что тот мой код (напомню — востмилетней давности) умеет еще выполнять trim по ходу дела, выделять токены в кавычках любого вида (аргумент "quote") с маскированием (аргумент mask_chr) и работать с тремя типами разделителей: MS>single — каждый символ является разделителем (1,,,2 выдаст "1" "" "" "2") MS>multiple — работает как strtok (1,,,2 выдаст "1" "2") MS>whole_str — разделителем является вся строка
Мне влом все это выписваать, но я тебяуверяю, что размер кода будет все равно не сопоставим с твоим.
MS>Все это не нужно в рамках задачи данного треда, но при этом и не мешает. Просто я наивно расчитывал на наличие у тебя некоторых зачатков разума.
Ага.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: BOOST, .NET, String.Split и производительность…
CC>Господа, ну ей богу как дети малые. Ну выводите вы в единых попугаях значения. Например в % от производительности на тестовой платформе самого первого приведенного исходника.
А как ты себе это видишь? Вообще-то тест 3 у меня как раз дотнетный сплит. Так что процент можешь посчитать сам.
За одно можно сделать вывод, что 30% производительности легко заменяются 30% стоимости процессора.
CC> Потому как понять, что быстрее — приведенный код на немерлях или написанный на коленке код на языке ЗЮ, если у меня нет немерле?
На самом, деле на Немерле можно написать код 1 в 1 и даже чуть быстрее чем версия из библоиотеки. Но какой смысл доказвать, что джит работат (просто работает)?
CC>А то скучно за вашими писькомерянием наблюдать когда не видно у кого короче
Откровенно говоря эта пенисометрия меня не волоновала. Меня интересовало насколько велик оверхэд у функционального подхода и итераторов. Ведь писать с их использованием иногда намного приятнее. И если это не так уж дорого стоит, то почему бы и нет. Самый разфункциональный варинт показал скорость куда выше чем тормоза на С++ (те что с библиотекой, а не с хардкодингом). Если мне захочется написать действительно максимально быстрый вариант, то я его напишу. Но он будет менее красив чем эти.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
CC>>Господа, ну ей богу как дети малые. Ну выводите вы в единых попугаях значения. Например в % от производительности на тестовой платформе самого первого приведенного исходника. VD>А как ты себе это видишь? Вообще-то тест 3 у меня как раз дотнетный сплит. Так что процент можешь посчитать сам.
Я имел в виду ту черепашку на С++ + буст. Которая 20 секунд ползла... Время других тестов выводить как % от времени исполнения этого черепашьего теста на этой же машине.
VD>За одно можно сделать вывод, что 30% производительности легко заменяются 30% стоимости процессора.
CC>> Потому как понять, что быстрее — приведенный код на немерлях или написанный на коленке код на языке ЗЮ, если у меня нет немерле? VD>На самом, деле на Немерле можно написать код 1 в 1 и даже чуть быстрее чем версия из библоиотеки. Но какой смысл доказвать, что джит работат (просто работает)?
Нененене! Теоретическое доказательство не интересует. Надо практическое. Потому как в теории — практика не отличается от теории. Но на практике — отличается. (С) "не помню кто"
CC>>А то скучно за вашими писькомерянием наблюдать когда не видно у кого короче VD>Откровенно говоря эта пенисометрия меня не волоновала.
Сама пенисометрия мне тоже по барабану. Мне больше интересно у которого варианта производительность выше, насколько и почему. VD>тормоза на С++ (те что с библиотекой, а не с хардкодингом).
Т.е. тормоза самого буста...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[5]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, McSeem2, Вы писали:
MS>>Если бы ты был чуть более внимательным, то заметил бы, что тот мой код (напомню — востмилетней давности) умеет еще выполнять trim по ходу дела, выделять токены в кавычках любого вида (аргумент "quote") с маскированием (аргумент mask_chr) и работать с тремя типами разделителей: MS>>single — каждый символ является разделителем (1,,,2 выдаст "1" "" "" "2") MS>>multiple — работает как strtok (1,,,2 выдаст "1" "2") MS>>whole_str — разделителем является вся строка
VD>Мне влом все это выписваать, но я тебяуверяю, что размер кода будет все равно не сопоставим с твоим.
Вообще то вполне сопоставим, эта не та задача на которй можно демонстрировать большие преимущества функциональщины, даже твой вариант в лоб переписанный на C++ не так уж и страшен:
вот результаты java. cpu = AMD Opteron 244 (1792.154Mhz). linux. jvm — sun, 1.5.0, 32bit.
используется только одно ядро, плюс надо бы сделать поправку на меньшую частоту камня...
import java.io.*;
import java.util.*;
class Test08 {
private static int test() {
int answer = 0;
final List<String> list = new ArrayList<String>();
final String text = "123 345 asdf 23453 asdfas".intern();
for (int i = 0; i < 1000000; i++) {
list.clear();
for (final StringTokenizer strtok = new StringTokenizer(text);
strtok.hasMoreTokens(); list.add(strtok.nextToken())) ;
answer += list.size();
}
return answer;
}
private static int test1() throws UnsupportedEncodingException {
int answer = 0;
final String [] array = new String[5];
final String text = "123 345 asdf 23453 asdfas".intern();
final byte space = " ".getBytes("windows-1251")[0];
final byte [] chars = text.getBytes("windows-1251");
final int clen = chars.length;
for (int i = 0, l = 0; i < 1000000; i++, l = 0) {
for (int c = 0, x = 0; c < chars.length; c++) {
if (chars[c] == space) {
array[l++] = text.substring(x, c);
x = c + 1;
} else if (c == chars.length - 1 && clen - x > 1) {
array[l++] = text.substring(x, clen);
}
}
answer += l;
}
return answer;
}
public static void x() {
long start = System.nanoTime();
System.out.println(test());
System.out.println((double)(System.nanoTime() - start) / 1.0e6);
}
public static void y() throws UnsupportedEncodingException {
long start = System.nanoTime();
System.out.println(test1());
System.out.println((double)(System.nanoTime() - start) / 1.0e6);
}
public static void main(String [] args) throws UnsupportedEncodingException {
for (int i = 0; i < 5; i++) x();
System.out.println("-------------");
for (int i = 0; i < 5; i++) y();
}
}
Здравствуйте, VladD2, Вы писали:
VD>Правильно ли я понял эти строки, что можно переименовывать только все методы с одинаковым мменем во всех классах одновременно? Или все же можно изменить имя метода в одном классе и оставить без изменений другие методы с тем же именем и списком параметров?
Можно.
Только маленькое замечание: из-за ключевых сообщений, не может быть два одинаковых метода с разными списками параметров.
VD>Если это возможно, то второй вопрос. Как среда отделяет вызовы методов в случае когда например, объект передается в качестве параметра и не ясно что за тип будет у этого объекта?
/Я могу рассказать только за VW. С другими средами я недостаточно знаком./
Автоматически — никак. Появляется превью откуда можно удалить лишние методы. По практике, переименовать стандартный метод, например, с именем printString (то что toString() в java) — абсолютно нереально. Невозможно и переименовать какой-то метод в другой, если метод с новым именем уже есть выше в иерархии. Это единственное ограничение, которое меня реально бесило. А вот со своими собственными методами проблем возникает мало, из-за того как образуются имена методов в ST. То есть они скорее уникальны чем нет.
Броузер так-же содержит функцию "Spawn" которая умеет открывать броузер в котором виден только отдельный выбранный пакет или иерархия классов. Что удивительно, функции "find senders/find implementors" учитывают эту информацию и ищут только в пределах отображаемого пакета (или нескольких пакетов), а вот рефакторилка эту информацию игнорит. Подозреваю, что поддержка подобного ограничения области видимости удовлетворила бы всех вообще
Здравствуйте, CreatorCray, Вы писали:
CC>Сама пенисометрия мне тоже по барабану. Мне больше интересно у которого варианта производительность выше, насколько и почему.
Очень похоже на строку из Двенадцати стульев: "Он бескорыстно любил деньги...".
На самом деле тут все очень просто. Языки имеющие компилирующий и оптимизирующий бэкнэнд позволяют написать подобный код с эффективностью близкой к ассемблерной реализации. Разницу до 1.5-2 раз могут составлять вычираемые компиляторами паттерны и качество оптимизации. Оптимальный вариант должен стараться избегать динамического выделения памяти, так как при таком объеме итераций (сентетическом, не реальным), это становится самым узким местом (что во всю присутствует в первом и последнем примере). Вторым узким местом будет использование виртульных методов (что во всю присутствует во втором моем примере). Но все это актуально если нет явных косяков вроде тех что опосредованно присуствуют в С++-коде.
Оптимальный с точки зрения быстродействия код обычно оказывается убогим и не красивым. Так что, как всегда за красоту приходится платить. Вот мне и интересно сколько стоит та самая красота. В бусте она оказалась неприемлемо дорга. А вот потери в дотнете изменяются в процентах, что лично мне кажется приемлемым.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Чтобы у людей лишних вопросов не возникало. Откровенно говоря оверхэд в тестах меня не трогает. Намного интереснее как выглядит алгоритм. Вот явщик меня в этом смысле порадовал
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Автоматически — никак. Появляется превью откуда можно удалить лишние методы.
Ясно. В очередной раз подтверждается старая истина, что чудес не бывает.
ANS> По практике, переименовать стандартный метод, например, с именем printString (то что toString() в java) — абсолютно нереально. Невозможно и переименовать какой-то метод в другой, если метод с новым именем уже есть выше в иерархии. Это единственное ограничение, которое меня реально бесило. А вот со своими собственными методами проблем возникает мало, из-за того как образуются имена методов в ST. То есть они скорее уникальны чем нет.
То есть в имя метода вы засовываете некую дополнительную информаци? Ясно. Это знакомо по С/С++. Меня как раз порадовало в Яве и дотнете, что в имена не надо ничего лишнего засовывать. Ну, да у СТ свои особенности.
ANS>Броузер так-же содержит функцию "Spawn" которая умеет открывать броузер в котором виден только отдельный выбранный пакет или иерархия классов. Что удивительно, функции "find senders/find implementors" учитывают эту информацию и ищут только в пределах отображаемого пакета (или нескольких пакетов), а вот рефакторилка эту информацию игнорит. Подозреваю, что поддержка подобного ограничения области видимости удовлетворила бы всех вообще
Откровенно говоря куда полезнее было бы все же ввести хоть какую-то аннотацияю типов. Хотя бы для параметров и возвращаемого значения методов. Ну, да это вроде тоже было в Строгтоке и он особо популярным не стал.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Доброго времени суток!
D>Понадобилось 'посплитить' строки (вообще задача более сложная, но обо всем по порядку), и по совету “мудрых старцев” (которые по новомодной традиции, при каждом чихе отправляют к boost-у) решил потестировать производительность boost::algoruthm:split.
D>Честно говоря, результаты меня обескуражили…
Я проводил тесты на компютере с процессором AMD Athlon XP 2500+ (частота 1.84 ГГц)
Исходный тест
{
int r = 0;
std::vector<std::string> tokens(5);
ttPerformanceCounter pc;
pc.Start();
for(int i = 0; i < 1000000; i++)
{
boost::split(tokens, "123 345 asdf 23453 asdfas", boost::is_any_of(" "));
r += tokens.size();
}
double sec = pc.Finish();
std::cout << "boost::is_any_of " << sec << " sec" << std::endl;
}
выполнялся в среднем за 21.1896 сеунды почти то же что и в оригинале
очень медленным оказался boost::is_any_of, скорее всего потому что сепараторы в нём хранятся так std::set<set_value_type> m_Set; и это отягощается тем что в смом split функтор хранится по значению.
при замене boost::is_any_of на
class IsSpace
{
public:
bool operator()(char c) const
{
return c == ' ';
}
};
получился резкий прирост производительности
в среднем время выполнения составило 5.17771 секунды
далее как ранее я писал, в split итераторе для храниения придиката который производит поиск сепараторов использовалась boost::function
замена её на непосредственно сам предикат позволила ещё немного сократить время выполнения
в среднем время выполнения составило 1.7099 секунды
далее ещё заменил аллокатор и вместо вектора взяд std::list
Здравствуйте, Андрей Хропов, Вы писали:
АХ>Не удержался от того, чтобы создать новую расширенную версию.
Вот что выдают твои тесты у меня на компе
тут я только добывал бустовский аллокатор
C++,boost,vector,is_any_of: res is 5000000,21859 ms elapsed
C++,boost,list,is_any_of: res is 5000000,20157 ms elapsed
C++,boost,vector,is_space: res is 5000000,6703 ms elapsed
C++,boost,list,is_space: res is 5000000,5734 ms elapsed
C++,boost,vector,myIsSpace: res is 5000000,5688 ms elapsed
C++,boost,list,myIsSpace: res is 5000000,4703 ms elapsed
C++,boost,vector,MyIsSpace: res is 5000000,5578 ms elapsed
C++,boost,list,MyIsSpace: res is 5000000,4547 ms elapsed
C++,boost,vector,boost::pool,is_any_of: res is 5000000,20750 ms elapsed
C++,boost,list,boost::pool,is_any_of: res is 5000000,18609 ms elapsed
C++,boost,vector,boost::pool,is_space: res is 5000000,6391 ms elapsed
C++,boost,list,boost::pool,is_space: res is 5000000,3906 ms elapsed
C++,boost,vector,boost::pool,myIsSpace: res is 5000000,5375 ms elapsed
C++,boost,list,boost::pool,myIsSpace: res is 5000000,3047 ms elapsed
C++,boost,vector,boost::pool,MyIsSpace: res is 5000000,5234 ms elapsed
C++,boost,list,boost::pool,MyIsSpace: res is 5000000,2860 ms elapsed
C++,VK,vector,function,val: res is 5000000,3593 ms elapsed
C++,VK,vector,function,ref: res is 5000000,3563 ms elapsed
C++,VK,list,function,val: res is 5000000,2250 ms elapsed
C++,VK,list,function,ref: res is 5000000,2281 ms elapsed
C++,Noname2,vector,function,val: res is 5000000,3594 ms elapsed
C++,Noname2,vector,function,ref: res is 5000000,3594 ms elapsed
C++,Noname2,list,function,val: res is 5000000,2406 ms elapsed
C++,Noname2,list,function,ref: res is 5000000,2344 ms elapsed
C++,VK,vector,functor,val: res is 5000000,3437 ms elapsed
C++,VK,vector,functor,ref: res is 5000000,3453 ms elapsed
C++,VK,list,functor,val: res is 5000000,2156 ms elapsed
C++,VK,list,functor,ref: res is 5000000,2157 ms elapsed
C++,Noname2,vector,functor,val: res is 5000000,3515 ms elapsed
C++,Noname2,vector,functor,ref: res is 5000000,3516 ms elapsed
C++,Noname2,list,functor,val: res is 5000000,2266 ms elapsed
C++,Noname2,list,functor,ref: res is 5000000,2265 ms elapsed
а это результаты тех же тустов но на boost::split который я модифицировал таким образом чтоб убрать оттуда boost::function (я писал об этом здесь
C++,boost,vector,is_any_of: res is 5000000,19047 ms elapsed
C++,boost,list,is_any_of: res is 5000000,17594 ms elapsed
C++,boost,vector,is_space: res is 5000000,4593 ms elapsed
C++,boost,list,is_space: res is 5000000,3453 ms elapsed
C++,boost,vector,myIsSpace: res is 5000000,3813 ms elapsed
C++,boost,list,myIsSpace: res is 5000000,2765 ms elapsed
C++,boost,vector,MyIsSpace: res is 5000000,3547 ms elapsed
C++,boost,list,MyIsSpace: res is 5000000,2609 ms elapsed
C++,boost,vector,boost::pool,is_any_of: res is 5000000,18282 ms elapsed
C++,boost,list,boost::pool,is_any_of: res is 5000000,15734 ms elapsed
C++,boost,vector,boost::pool,is_space: res is 5000000,4344 ms elapsed
C++,boost,list,boost::pool,is_space: res is 5000000,2062 ms elapsed
C++,boost,vector,boost::pool,myIsSpace: res is 5000000,3516 ms elapsed
C++,boost,list,boost::pool,myIsSpace: res is 5000000,1312 ms elapsed
C++,boost,vector,boost::pool,MyIsSpace: res is 5000000,3344 ms elapsed C++,boost,list,boost::pool,MyIsSpace: res is 5000000,1156 ms elapsed
C++,VK,vector,function,val: res is 5000000,3219 ms elapsed
C++,VK,vector,function,ref: res is 5000000,3188 ms elapsed
C++,VK,list,function,val: res is 5000000,2156 ms elapsed
C++,VK,list,function,ref: res is 5000000,2156 ms elapsed
C++,Noname2,vector,function,val: res is 5000000,3375 ms elapsed
C++,Noname2,vector,function,ref: res is 5000000,3375 ms elapsed
C++,Noname2,list,function,val: res is 5000000,2313 ms elapsed
C++,Noname2,list,function,ref: res is 5000000,2390 ms elapsed
C++,VK,vector,functor,val: res is 5000000,3094 ms elapsed
C++,VK,vector,functor,ref: res is 5000000,3094 ms elapsed
C++,VK,list,functor,val: res is 5000000,2078 ms elapsed
C++,VK,list,functor,ref: res is 5000000,2094 ms elapsed
C++,Noname2,vector,functor,val: res is 5000000,3422 ms elapsed
C++,Noname2,vector,functor,ref: res is 5000000,3437 ms elapsed
C++,Noname2,list,functor,val: res is 5000000,2250 ms elapsed
C++,Noname2,list,functor,ref: res is 5000000,2266 ms elapsed
как видно самым быстрым является boost::split (поправленный немного) и std::list с boost::fast_pool_allocator
Re[2]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
VD>То есть в имя метода вы засовываете некую дополнительную информаци? Ясно. Это знакомо по С/С++. Меня как раз порадовало в Яве и дотнете, что в имена не надо ничего лишнего засовывать. Ну, да у СТ свои особенности.
Я бы сказал, что у "ключевых сообщений" имена с доп.информацией получаются сами собой. Ну, типа тех
at: aKey ifAbsent: [...action...]
и
at: aKey ifAbsentPut: [...some value...]
И в Java мне не нравится именно то, что такие "полные" имена смотрятся там очень неестественно.
VD>Откровенно говоря куда полезнее было бы все же ввести хоть какую-то аннотацияю типов. Хотя бы для параметров и возвращаемого значения методов. Ну, да это вроде тоже было в Строгтоке и он особо популярным не стал.
Ну, ему как бы и не дали. Но история не терпит сослагательных наклонений. Так что гадать не будем.
если уж вы настаиваете чтобы ArrayList аллоцировался миллион раз — пожалуйста. но, intern() не надо делать в цикле тогда, это JNI вызов и он имеет смысл только в некоторых случаях. кроме того, надо дать JVM несколько секунд на то, чтобы он скомпилировал код (либо проставить специальные флаги в command line). и ОБЯЗАТЕЛЬНО использовать -server.
вот такой код:
import java.util.*;
import java.io.*;
class Test08 {
private static int test() {
int answer = 0;
for (int i = 0; i < 1000000; i++) {
final List<String> list = new ArrayList<String>();
final String text = "123 345 asdf 23453 asdfas";
for (final StringTokenizer strtok = new StringTokenizer(text);
strtok.hasMoreTokens(); list.add(strtok.nextToken())) ;
answer += list.size();
}
return answer;
}
private static int test1() throws UnsupportedEncodingException {
int answer = 0;
final char space = " ".charAt(0);
for (int i = 0; i < 1000000; i++) {
final List<String> list = new ArrayList<String>();
final String text = "123 345 asdf 23453 asdfas";
final char [] chars = text.toCharArray();
final int clen = chars.length;
for (int c = 0, x = 0; c < clen; c++) {
if (chars[c] == space) {
list.add(text.substring(x, c));
x = c + 1;
} else if (c == chars.length - 1 && clen - x > 1) {
list.add(text.substring(x, clen));
}
}
answer += list.size();
}
return answer;
}
public static void x() {
long start = System.nanoTime();
System.out.println(test());
System.out.println((double)(System.nanoTime() - start) / 1.0e6);
}
public static void y() throws UnsupportedEncodingException {
long start = System.nanoTime();
System.out.println(test1());
System.out.println((double)(System.nanoTime() - start) / 1.0e6);
}
public static void main(String [] args) throws UnsupportedEncodingException {
for (int i = 0; i < 5; i++) x();
System.out.println("-------------");
for (int i = 0; i < 5; i++) y();
}
}
лучшего, что смог добиться от вышеприведенного кода, это
~631ms — StringTokenizer (в среднем за 20 проходов)
~477ms — самописный код (в среднем за 20 проходов)
на BEA jrockit-R26.4.0 используя коммандную строку java -server -cp . -Xmx256m -Xms256m -XXaggressive:opt Test08
кстати, я правильно понимаю что D/C/C++ варианты оперирует с 8битными ASCII строками? ИМХО, скорее всего, именно это дает им определенное приемущество.
Java использует UTF16 и соот-но строка может содержать огромное кол-во кодировок.
Re[4]: [Benchmark]:updated - Split на C++,D,C#,Nemerle,Boo,J
n0name2 wrote: > private static int test() { > int answer = 0; > final List<String> list = new ArrayList<String>(); > final String text = "123 345 asdf 23453 asdfas".intern(); > for (int i = 0; i < 1000000; i++) { > list.clear(); > for (final StringTokenizer strtok = new StringTokenizer(text); > strtok.hasMoreTokens(); list.add(strtok.nextToken())) ; > answer += list.size(); > } > return answer; > }
Для подсчета количества токенов хватит и такого кода
private static int test() {
int answer = 0;
String text = "123 345 asdf 23453 asdfas";
for (int i = 0; i < 1000000; i++) {
final StringTokenizer strtok = new StringTokenizer(text);
answer += strtok.countTokens();
}
return answer;
}
Posted via RSDN NNTP Server 2.0
Re[3]: [Benchmark]:updated - Split на C++,D,C#,Nemerle,Boo,J
Здравствуйте, n0name2, Вы писали:
N>кстати, я правильно понимаю что D/C/C++ варианты оперирует с 8битными ASCII строками? ИМХО, скорее всего, именно это дает им определенное приемущество. N>Java использует UTF16 и соот-но строка может содержать огромное кол-во кодировок.
Думаю все проще. D или вооще не использует GC для локальных строк или его GC очень примитивен и на таких тестах дает выигрышь. А Явский GC рассчитан на рботу с огромными массивми объектов и на таких примитивных задачах себя проявить не может.
А вообще приводить результаты тестов без указания процессоров это очень правильно.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [Benchmark]:updated - Split на C++,D,C#,Nemerle,Boo,J
n0name2 wrote: > class Test08 { > private static int test() { > int answer = 0; > for (int i = 0; i < 1000000; i++) { > final List<String> list = new ArrayList<String>(); > final String text = "123 345 asdf 23453 asdfas"; > for (final StringTokenizer strtok = new StringTokenizer(text); > strtok.hasMoreTokens(); list.add(strtok.nextToken())) ; > answer += list.size(); > } > return answer; > }
Во всех примерах был только подсчет токенов и не нужно было
инициализировать никаких масивов поэтому еще раз говорю — нужно просто
использовать конструкцию вида
final StringTokenizer strtok = new StringTokenizer(text);
answer += strtok.countTokens();
Posted via RSDN NNTP Server 2.0
Re[4]: [Benchmark]:updated - Split на C++,D,C#,Nemerle,Boo,J
Здравствуйте, VladD2, Вы писали:
N>>кстати, я правильно понимаю что D/C/C++ варианты оперирует с 8битными ASCII строками? ИМХО, скорее всего, именно это дает им определенное приемущество. N>>Java использует UTF16 и соот-но строка может содержать огромное кол-во кодировок. VD>Думаю все проще. D или вооще не использует GC для локальных строк или его GC очень примитивен и на таких тестах дает выигрышь. А Явский GC рассчитан на рботу с огромными массивми объектов и на таких примитивных задачах себя проявить не может.
на самом деле процент CPU который занимает GC в данном тесте ничтожно мал т.к. живые объекты в некий момент времени можно посчитать по пальцам (StringTokenizer, ArrayList и максимум пяток строк). Если версия с разрядностью символов отпадает, то у меня остается версия с тем, что в C/C++ строки можно аллоцировать на стеке. К сожалению, в Java6 не успели в Mustang включить данную фичу и Escape Analysis используется пока только для удаления неиспользуемых synchronized блоков (что, конечно, тоже хорошо, но, в микробенчмарках не всегда получается это показать)...
VD>А вообще приводить результаты тестов без указания процессоров это очень правильно.
Кстати, удалось еще немного выжать из вышеприведенного кода задействовав TLA по полной программе (Thread Local Allocation, т.е. объекты аллоцируются не в общей куче а в отдельной для каждого потока см. http://edocs.bea.com/jrockit/geninfo/memman/concepts.html)
[denis@ds-3748:~/tmp]$ time /usr/java/jrockit-R26.4.0-jdk1.5.0_06/bin/java -server -cp . -Xmx256m -Xms256m -XXaggressive -XgcReport -XXthroughputCompaction -XXlargeObjectLimit6K -XXtlaSize128k Test08
583.8475263999999
392.6505215999998
[memory ]
[memory ] Memory usage report
[memory ]
[memory ] old collections
[memory ] number of collections = 86
[memory ] total promoted = 0 (size 0)
[memory ] max promoted = 0 (size 0)
[memory ] total GC time = 0.597 s (pause 0.597 s)
[memory ] mean GC time = 6.945 ms (pause 6.945 ms)
[memory ] maximum GC Pauses = 11.461 , 13.531, 32.736 ms
[memory ]
[memory ] number of parallel mark phases = 86
[memory ] number of parallel sweep phases = 86
real 0m53.842s
user 0m54.408s
sys 0m0.560s
GC занял всего 0.6сек из 54сек, второе ядро практически не использовалось т.к. user > real всего на 0.8сек.
[denis@ds-3748:~/tmp]$ /usr/java/jrockit-R26.4.0-jdk1.5.0_06/bin/java -server -version
java version "1.5.0_06"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
BEA JRockit(R) (build R26.4.0-63-63688-1.5.0_06-20060626-2259-linux-ia32, )
[denis@ds-3748:~/tmp]$ uname -a
Linux ****** 2.6.9-34.ELsmp #1 SMP Fri Feb 24 16:54:53 EST 2006 i686 athlon i386 GNU/Linux
JavaBean,
.countTokens() использовать нельзя т.к. тестируется не подсчет кол-ва токенов а именно split на список строк.
Re[5]: [Benchmark]:updated - Split на C++,D,C#,Nemerle,Boo,J
Здравствуйте, n0name2, Вы писали:
N>на самом деле процент CPU который занимает GC в данном тесте ничтожно мал т.к. живые объекты в некий момент времени можно посчитать по пальцам (StringTokenizer, ArrayList и максимум пяток строк).
На самом деле (с) GC жрет время не только во время сборки мусора, но и во время выделения памяти. Он рассчитан на работу в многопоточной среде и делает блокировки. Так что если сокнурент не делает блокировок или вообще использует стэк для хранения результатов, то скорость у него будет значительно выше. Но это в таких примитивных тестах. А в реальных условиях все компенсируется.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: [Benchmark]:updated - Split на C++,D,C#,Nemerle,Boo,J
Здравствуйте, VladD2, Вы писали:
VD>На самом деле (с) GC жрет время не только во время сборки мусора, но и во время выделения памяти. Он рассчитан на работу в многопоточной среде и делает блокировки. Так что если сокнурент не делает блокировок или вообще использует стэк для хранения результатов, то скорость у него будет значительно выше. Но это в таких примитивных тестах. А в реальных условиях все компенсируется.
собственно, за счет TLA удалось улучшить время исполнения с ~500ms до ~400ms. ну, и за счет некоторых других опций (в т.ч. другой стратегии memory compactification).
The allocating Java thread requests a thread-local area (TLA) from the nursery (generational garbage collector) or from the heap (single-generational garbage collector) for allocation of these objects. The TLA is reserved from the heap or the nursery and given to the thread for exclusive use. This allows the thread to allocate small objects in its own TLA without taking any kind of lock. When the TLA gets full the thread simply requests a new TLA.
a thread will try to allocate the object in the currently held TLA. It puts the object at the beginning of the free space in the TLA and moves the free space pointer forward to the end of the object.
плюс ко всему и строки несколько по другому по сравнению с C работают, сама строка это ссылка на массив char [], плюс индекс начала и длинна а не просто ссылка на данные. всякие runtime проверки на индекс в массиве и т.д.
Re[8]: [Benchmark]:updated - Split на C++,D,C#,Nemerle,Boo,J
Здравствуйте, VladD2, Вы писали:
VD>Исходников не вижу, так что и сказать ничего не могу. Но TLA (это видимо то что под Виндовс назвается LTS, т.е. локальное хранилище потока), тоже не беслатное. Оно значительно медленее стековой переменной. Так что на С всегда можено сделать чуточку быстрее.
с т.з. исходников использование TLA (в BEA имплементации JVM) или TLAB (так это называется в Sun имплементации JVM) полностью прозрачно. т.е. обчыный new делается не в основном heap а в TLA cache. виндовые TLS требуют явного использования, да и это несколько другая фишка вообще.
TLA/TLAB в Java это просто способ аллокации памяти, когда потоку выделяется сразу большой кусок памяти (скажем, 512kb) и после этого он внутри его аллоцирует мелкие объекты вроде строк, массивов и т.п. причем, уже нет необходимости синхронизировать аллокацию с другими потоками.
VD>Вот только кому это нужно. Код подобных оптимизаций неприлично большой.
как раз Sun придерживается той политики что такого рода оптимизации происходят на 100% внутри JVM и программисты об этом думать не должны в момент написания кода. именно поэтому value типы не были реализованы, по мнению Sun это должно (и будет) делаться с помощью escape analysis.
Re[12]: BOOST, .NET, String.Split и производительность…
Здравствуйте, VladD2, Вы писали:
FR>>Там на самом деле частично виноват ms только не писатели операционки, а те кто писал рантайм к VC. Поэтому та же первоначальная версия теста откомпилированная со STLPort отрабатывает в полтора раза шустрее.
VD>Извини, а 1.5 раза и 30 раз проигрыша C#-e это сравненимые вещи? А под Линуксом что тормоизило?
VD>А может это и правда заговор? Ну, МС специально подкупили всех писателей библиотек?
Я малость недоумеваю. Вы тут всерьез спорите или как? В С++ строки передаются по значению, то бишь копируются (В C# — по ссылке). Причем, каждый раз создается копия в стандартной куче. Кстати, никто не догадался прогнать этот тест ну хотя бы в однопоточной версии CTR? Или прикрутить минимальный аллокатор для локальной кучи (можно в виндах получить кучу в свое единоличное распоряжение). Там же блокировка происходит каждый раз при обращении к стандартному пулу памяти.
И для таких задач, как правильно заметили, есть const_string. Но опять же, выигрышь будет только со локальным, по отношению к треду, пулом памяти, где брать и возвращать память можно без блокировок.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Ну мужики, я ведь только заглянул в split и увидел большое количество копирований предиката. А дальше я не смотрел. Очень вероятно, что сам алгоритм поиска и выделения подстрок грешит таким же избыточным количеством копирований и передачи аргументов по значению.
Да, предикаты должны иметь нулевые издержки при копировании. В STL те же грабли. Либо можно явно указывать не сам тип предиката, а константную ссылку на него. Т.е. создать предикат на стеке, а при вызове ф-ции явно указать тип константной ссылки на предикат в аргументах шаблона.
Ну и так же я опять прошу проверить это все на однопоточной версии рантайма.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[9]: BOOST, .NET, String.Split и производительность…
Здравствуйте, vdimas, Вы писали:
V>Уже обсуждали. Бустовская лямбда хороша для мелких вещей по-месту. Для "крупных" нет проблем нарисовать 2 лишние строки для введения своего функтора:
А Obj.Prop1.Prop2.Prop3 это крупный или мелкий случай?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, cattus, Вы писали:
АХ>>Померил с использованием таймеров (чтобы не учитывать JIT компиляцию) АХ>>Вот результаты (усреднены по 10 запускам) АХ>>(Athlon XP 1700+ @ 1.5 GHZ + 512Mb DDR266) АХ>>:
АХ>>1) DMD — 0.775 сек АХ>>2) GDC — 0.905 сек АХ>>3) С#/Nemerle — 1.1 сек АХ>>4) Python — 3.48 сек АХ>>5) Python+Psyco — 4.12 (не ускорил!) АХ>>6) GCC + Boost — 22.5 сек АХ>>7) MS VC++ + Boost — 35 сек
C>Вот еще одно подтверждение изначальной ущербности теста. Прошу сильно не пинать за код -- я очень долго ничего не писал на Haskell'е.
Здравствуйте, vdimas, Вы писали:
V>Я малость недоумеваю. Вы тут всерьез спорите или как? В С++ строки передаются по значению, то бишь копируются (В C# — по ссылке). Причем, каждый раз создается копия в стандартной куче. Кстати, никто не догадался прогнать этот тест ну хотя бы в однопоточной версии CTR? Или прикрутить минимальный аллокатор для локальной кучи (можно в виндах получить кучу в свое единоличное распоряжение). Там же блокировка происходит каждый раз при обращении к стандартному пулу памяти.
boost::pool прикручивал польза близкая к нулю.
Re[5]: [Benchmark]:updated - Split на C++,D,C#,Nemerle,Boo,J
n0name2 wrote: > JavaBean, > .countTokens() использовать нельзя т.к. тестируется не подсчет кол-ва > токенов а именно split на список строк.
Учел твои пожелания
private static int test() {
int answer = 0;
for (int i = 0; i < 1000000; i++) {
answer+=StringUtils.split("123 345 asdf 23453 asdfas", "
").length;
}
return answer;
}
Для сплита была взята либа commons lang 2.1
5000000
1139.989
Posted via RSDN NNTP Server 2.0
Re[6]: [Benchmark]:updated - Split на C++,D,C#,Nemerle,Boo,J
Здравствуйте, vdimas, Вы писали:
V>Вообще-то нет. Посмотри, там действительно несколько вложенных if-ов. Имеет ли смысл их декомпозировать?
Имеет, если в языке есть средства которыми это можно сделать. В С++ с ними туго, вот и получаются монстрики.
Я когда пишу такой код, то чувствую что халтурю. По крайней мере получить удовлетворения от такого я не могу. Удовлетворительный код почему-то всегда получается за одно и хорошо структурированным (с хорошей декомпозицией).
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.