LINUX.ORG.RU

Контейнеры в C


2

3

Будучи сиплюсплюсником, меня давно интересует как те же задачи выполняются в C. Знаю, на ЛОРе есть множество приверженцев C, надеюсь они ответят на пару простых вопросов.

Я являюсь активным сторонником идеи «Алгоритм должен работать настолько быстро, насколько позволяет железо». С этой точки зрения C++ даёт потрясающие возможности из-за своей системы кодогенерации. Да, я имею в виду шаблоны.

Не будем зарываться в дебри boost'а, возьмём простую задачу - контейнеры.

Для примера я взял односвязные списки в GTK GSList и Qt QList. QList позволяет хранить как простые, так и сложные типы с конструкторами, деструкторами, типы с общими данными. При этом накладных расходов на выделение в куче не происходит, а при реаллокации выбирается нужный алгоритм в зависимости от QTypeInfo<T>, к примеру для int будет вызван memcpy(), а для QString оператор копирования. Кроме того блок данных заранее резервируется и для сложных типов вызывается placement constructor. Для удаления данных по указателям используется алгоритм qDeleteAll(from,to), который сам дёрнет нужные конструкторы. Беглый просмотр GSList показал, что в нём можно хранить только указатели, со всеми вытекающими накладными расходами на аллокацию/уничтожение памяти, ручное кастирование, слежение за утечками, фрагментацию памяти.

Аналогичная ситуация со связными списками GList и QLinkedList.

Это даже не затрагивая вопрос о типизации, в C++ компилятор сразу даст по рукам при попытке записать в контейнер неверный тип или с помощью неявного преобразования с explicit-конструктором.

Далее, счётчики ссылок и деструкторы.

К примеру, в C++ список строк будет выглядеть как QList<QString>, при этом можно забыть про внутреннюю структуру строки - конструктор, деструктор и операторы копирования сами занимаются подсчётом ссылок, разделением и уничтожением данных. Вернуть строку из функции проще простого:

QString foo()
{
    return listOfStrings.at( 5 );
}

Этот код абсолютно безопасен и оптимален с точки зрения использования памяти и процессора, поскольку время тратится только на увеличение счётчика и копирование указателя.

В GTK я сходу нашёл GString:

struct GString 
{
  gchar *str;
  gint len;
};

Причём экземпляры этой структуры выделяются в куче. Никаких счётчиков ссылок не видно, значит при обычном присваивании нужно или руками следить за всеми указателями на строку, или каждый раз делать глубокое копирование, опять же тратя и фрагментируя память и ресурсы процессора.

Собственно, мне интересно каков принцип работы сишников в таких простых задачах. Наплевать на производительность, выделять всё в куче, делать глубокое копирование сложных структур, всегда следить за кастированием к нужному типу, писать для любой структуры деструктор и следить за его вызовом?

Или может GTK неудачный пример, тогда дайте ссылку на правильную C-библиотеку с контейнерами.

★★★★★
Ответ на: комментарий от namezys

>В питоне их еще больше.

Я бы постеснялся упоминать эту поделку в треде, где идет дискуссия о настоящих языках программирования. Пистон — это так, детсадовская игрушка.

linuxfan
()
Ответ на: комментарий от shelA

>А почему ты его в си юзаешь, а я в плюсах не могу? Считаешь себя умней других?

О чем тогда спор, если C++ — это надмножество C89? Мы тут вообще-то сравниваем плюсовый стиль с сишным. Если у тебя плюсовая программа изобилует new и delete, занчит ты ничерта не смыслишь в плюсах.

Я так понял использование в С++ char* есть «миксованная лапша из C и C++». Ну,ну я посмеялсо)))

Если у тебя в одном приложении со строками работа происходит как с QString, std::string и char*, то я опять-таки вежливо и настойчиво прошу тебя покинуть профессию программиста.

Где кстате ссылка на быстрый и безглючный браузер на Си. А то в мозиллу какашками покидал, а ответить нечем.

А его и нет. Однако отсутствие хорошего браузера не делает фаерфокс менее тормознутым.

linuxfan
()
Ответ на: комментарий от linuxfan

> А его и нет. Однако отсутствие хорошего браузера не делает фаерфокс менее тормознутым.

Кривость программистов не делает язык плохим

namezys ★★★★
()
Ответ на: комментарий от pathfinder

>А что мне помешает подобное написать на С++? Религия?

То, что это будет не C++. Это будет в лучше млучае «C с классами».

linuxfan
()
Ответ на: комментарий от namezys

>Кривость программистов не делает язык плохим

Тезис: плюсы — язык подтекающих абстракций, потому он плохой. У тебя, как я понимаю, другое мнение на этот счет?

linuxfan
()
Ответ на: комментарий от linuxfan

Конечно другое: нельзя все писать низкоуровнево, надеясь, что удастся договориться со всему участниками (когда даже сам с собой договориться не всегда можешь)

Но вы пишите, пишите. Короткие и простые программы иногда даже работают. Иногда даже быстро

namezys ★★★★
()
Ответ на: комментарий от linuxfan
struct Person { 
    char *nick; 
    char name[0]; 
}

С массивами нулевого размера надо быть осторожнее, размер структур с ними может плавать, в зависимости от компилятора. Тут можно схватить лютый батхерт.

http://www.xakep.ru/magazine/xa/106/126/1.asp

pathfinder ★★★★
()
Ответ на: комментарий от namezys

Хвала всевышнему, что основную часть линакса писали (и, надеюсь, пишут) не такие люди как ты. Иначе rm был бы монструозен.

linuxfan
()
Ответ на: комментарий от linuxfan

> Иначе rm был бы монструозен.

А по моему, был бы короче, чем сейчас

namezys ★★★★
()
Ответ на: комментарий от linuxfan

>> А что мне помешает подобное написать на С++? Религия?

То, что это будет не C++. Это будет в лучше млучае «C с классами».

Сформулируешь кратенько отличие Ъ-Си++ от «Си с классами»?

tailgunner ★★★★★
()
Ответ на: комментарий от linuxfan

Если я напишу map < string, string > , то это будет C++, а если напишу map < char *, char * >, то он вдруг станет «C с классами» ?

Reset ★★★★★
()
Ответ на: комментарий от tailgunner

>> То, что это будет не C++. Это будет в лучше млучае «C с классами».

Сформулируешь кратенько отличие Ъ-Си++ от «Си с классами»?

Я над этим его заявлением так уржался, что под стол чуть не свалился ))) Судя по всему у него какой-то особый, неведомый нам С++ есть. И это чудило еще советует мне «покинуть профессию программиста» )))

shelA
()
Ответ на: комментарий от linuxfan

> Если у тебя плюсовая программа изобилует new и delete, занчит ты ничерта не смыслишь в плюсах.

Долго думал над этим заявлением?)))

Если у тебя в одном приложении со строками работа происходит как с QString, std::string и char*

Ну QString не юзаю не до QT сейчас. А std::string и char* в одной программе успешно и неоднократно )))

Где кстате ссылка на быстрый и безглючный браузер на Си. А то в мозиллу какашками покидал, а ответить нечем.

А его и нет. Однако отсутствие хорошего браузера не делает фаерфокс менее тормознутым.

Охбле, какая досада ))) И к чему бы это, как думаешь?

shelA
()
Ответ на: комментарий от linuxfan

> Я бы постеснялся упоминать эту поделку в треде, где идет дискуссия о настоящих языках программирования.

Ийлита? Лисп волокешь?)

shelA
()
Ответ на: комментарий от Reset

>>Это не пара строк и даже не несколько, а десяток.

Если опустить декларации и тестовый вывод, то получится ровно две (2) строчки для аналога того, что просили.

Освобождение ресурсов стыдливо опустил ? Этот пример не эквивалентен C++ коду, ибо тут нет отсортированности и ключом может быть только строка.

А где ты видел освобождение ресурсов в тех двух строчках на крестах? И да, я не рассматривал общие случаи, а сделал лишь АНАЛОГ того, что меня попросили. Задача выполнена? Выполнена.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от shelA

>>а ТС хотел увидеть собственно еще и как организовать копирование объекта и удаление из списка и все это с «автоматическим» распределением/удаление памяти.

У ТС в голове какая-то хрень, потому что он хочет того, для сего С не создавался. Может ему gc в крестах понадобится, и что, кресты будут виноваты?

А уж если сделать проверку типа объекта на который ссылается указатель, наберется страниц еще несколько (в С++ это можно переложить на компилятор),

Еще один параноик. ЗАЧЕМ мне это делать, если я знаю, где у меня какие данные?

MuZHiK-2 ★★★★
()
Ответ на: комментарий от MuZHiK-2

Да, если упустим - то не станет ясно, сколько там гемора с этим

Освобождение ресурсов там есть. При выходе объекта из области выдимости

namezys ★★★★
()
Ответ на: комментарий от MuZHiK-2

> Еще один параноик. ЗАЧЕМ мне это делать, если я знаю, где у меня какие данные?

Зачем мне проверять, если ли фаил, если он там ДОЛЖЕН лежать

namezys ★★★★
()
Ответ на: комментарий от MuZHiK-2

А где ты видел освобождение ресурсов в тех двух строчках на крестах?

Они там есть неявно.

Задача выполнена?

нет

Reset ★★★★★
()
Ответ на: комментарий от MuZHiK-2

> Еще один параноик. ЗАЧЕМ мне это делать, если я знаю, где у меня какие данные?

Я параноик?) Ты знаешь где у тебя какие данные в твоей военной железке. А если это большой проект, который пишется на Си с использованием ООП костылей в несколько рыл. Не факт, что ты будешь знать где какие у тебя данные.

shelA
()
Ответ на: комментарий от namezys

>>Освобождение ресурсов там есть. При выходе объекта из области выдимости

Из видимости тех двух строчек я никуда не выхожу.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от shelA

>>Я параноик?) Ты знаешь где у тебя какие данные в твоей военной железке. А если это большой проект, который пишется на Си с использованием ООП костылей в несколько рыл. Не факт, что ты будешь знать где какие у тебя данные.

И как же люди в опенсурсе-то пишут...

MuZHiK-2 ★★★★
()
Ответ на: комментарий от tailgunner

>Сформулируешь кратенько отличие Ъ-Си++ от «Си с классами»?

Я каждому местному троллю обязан восполнять пробелы в образовании?

linuxfan
()
Ответ на: комментарий от MuZHiK-2

Ви идиот? Хватит строить из себя дурочку. Из области видимости переменых

namezys ★★★★
()
Ответ на: комментарий от MuZHiK-2

> И как же люди в опенсурсе-то пишут...

Так и получается GTK. Сравни с Qt или с cocao

namezys ★★★★
()
Ответ на: комментарий от linuxfan

>> Сформулируешь кратенько отличие Ъ-Си++ от «Си с классами»?

Я каждому местному троллю обязан восполнять пробелы в образовании?

Видимо, не сформулируешь.

tailgunner ★★★★★
()
Ответ на: комментарий от MuZHiK-2

> И как же люди в опенсурсе-то пишут...

Вот и мне интересно - как? Чем лить множество слов - лучше приведите полное решение вот этой вот задачи:

Написать модуль, который позволяет хранить список с ником и именем и по нику находить имя в этом списке. При этом иметь возможность из клиентского кода итерироваться по всему списку.

Dendy ★★★★★
() автор топика
Ответ на: комментарий от Dendy

Написать модуль, который позволяет хранить список с ником и именем и по нику находить имя в этом списке.

Элементарно: man sqlite :)

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Dendy

Как видим в C++ с помощью шаблона ликвидируется накладные расходы на аллокацию лишних данных в куче, в C же всё хранится по указателю.

Твой идиотизм и, главное, полное непонимание вопроса меня уже достало, поэтому пришло время макнуть тебя глубже. Я даже не поленился и написал небольшой тест для списков (можешь написать аналогичный для массивов, только смотри, не выпрыгни из окна от неожиданных результатов). Итак, Qt4 и твой указанный выше QLinkedList, который, как ты заявляешь, супер-пупер оптимальный:

struct person
{
    QString nick;
    int id;
};

int main(int argc, char *argv[])
{
    QLinkedList <person> list;

    for (int i = 0; i < 100000; ++i) {
        person per = {"Dendy", i};
        list.append (per);
    }
}

Как видишь, простенький тест на добавление 100 К элементов. Никакой магии. Аналогичный тестик на С с использованием GLib и GList:

#include <glib.h>

	typedef struct {
		gchar* nick;
		gint id;
	} person;

int main(int argc, char** argv)
{
	GList *list = NULL;
	guint i;

	for (i = 0; i < 100000; ++i) {
		person *Prs = g_slice_new (person);
		Prs->nick = g_strdup ("Dendy");
		Prs->id = i;
		list = g_list_prepend (list, Prs);
	}

	list = g_list_reverse (list);

	return 0;
}

Как видишь, я выделяю память в куче (на что ты и сетовал так активно) и работаю тут с указателями (и даже пришлось скопировать строчку, на что ты тоже там нес пургу). Теперь результаты тестов (через команду time). Для теста Qt4 в среднем (+- 0.002s)

real	0m0.062s
user	0m0.056s
sys	0m0.004s

Для теста GLib (+- 0.002s):

real	0m0.040s
user	0m0.032s
sys	0m0.008s

О, ужас! Qt4 сливает порядка 30% по скорости на такой простенькой задачке! А что будет дальше? Ясно дело, хуже. Так я не расслышал, что ты там за чушь нес про оптимальность и запупенность, скорость и форсаж своих любимых крестов?

В итоге код обьектника на C не сможет быть скомпилирован оптимально. Отсюда у меня возникает вывод, что в реальных задачах программисты на C жертвуют скоростью работы ради простоты кода.

Отсюда возникает вывод, что в реальности с С ты даже близко не знаком и тебе не помешало бы чему-то научиться и узнать, а главное, проверить, прежде чем постить непонятные и неаргументированные высеры, основанные на своих потугах что-то придумать.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от MuZHiK-2

Еще веселее будет без кэширования отсортировать такой список на пару миллионов элементов или найти в нем что-нибудь :)

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

>>Еще веселее будет без кэширования отсортировать такой список на пару миллионов элементов или найти в нем что-нибудь :)

Ну я уж не стал так жестко макать слоника и Ко, все крестовые навороты дадут просадку процентов в 50, наверно :)

MuZHiK-2 ★★★★
()
Ответ на: комментарий от namezys

>>И какие опции компилятора?

Опции компилятора я вообще не трогал - то, что по дефолту у креатора для Qt, и то, что выдает pkg-config для glib-теста.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от namezys

>>Попробуй QList для начала.

Проверил только что - абсолютно такой же результат.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от Dendy

>>Вот и мне интересно - как?

Ты знаешь, лично я даже не напрягаюсь почему-то. Как и они, наверно.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от MuZHiK-2

Как мне скомпилить прогу вторую?

Да, и вы забыли о том, что вообще-то строки в Qt юникодные, и вы за одно их конвертите

namezys ★★★★
()
Ответ на: комментарий от namezys

>>Как мне скомпилить прогу вторую?

gcc -o <prog_name> `pkg-config --cflags --libs glib-2.0` <main.c>

Да, и вы забыли о том, что вообще-то строки в Qt юникодные, и вы за одно их конвертите

Передал обоим тестам пустые строчки - у обоих время сократилось, но Qt все равно проигрывает процентов 30.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от MuZHiK-2

Можно еще проверить реализацию связанных списков без всяких «глистов»: на чистом С. Что-то вроде

struct person{
   char* nick;
   int id;
   struct person *prev;
   struct person *next;
}

struct person *newperson(){
   struct person *ptr = (struct person*)malloc(sizeof(struct person));
   return ptr;
}

struct person *addperson(struct person *last){
   struct person ptr = newperson();
   if(!last){
      ptr->prev = NULL;
      ptr->next = NULL;
   }
   else{
      if(!last->next){
        last->next = ptr;
        ptr->prev = last;
        ptr->next = NULL;
      }
      else{
        ptr->next = last->next;
        last->next->prev = ptr;
        last->next = ptr;
        ptr->prev = last;
      }
   return ptr;
}
и т.д.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от namezys

Ну мужик, я сам разобрался.

Qt:

#include <QString>
#include <QList>

const QString dendy = "Dendy";
 
struct person 
{ 
    person(const QString& a_nick, int a_id) :
        nick(a_nick), id(a_id) {}

    QString nick; 
    int id; 
}; 
 
int main(int argc, char *argv[]) 
{
    Q_UNUSED(argc);
    Q_UNUSED(argv); 
    QList<person> list; 
 
    for (int i = 0; i < 1000000; ++i) { 
        list.append( person(dendy, i) ); 
    } 
} 
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -I. -o a.o a.cpp
g++ -Wl,-O1 -o qt a.o    -L/usr/lib -lQtGui -lQtCore -lpthread

glib:

#include <glib.h> 

const char* dendy = "Dendy";
 
typedef struct { 
   gchar* nick; 
   gint id; 
} person; 
 
int main(int argc, char** argv) 
{ 
   GList *list = NULL; 
   guint i; 
 
   for (i = 0; i < 1000000; ++i) { 
      person *Prs = g_slice_new (person); 
      Prs->nick = g_strdup (dendy); 
      Prs->id = i; 
      list = g_list_prepend (list, Prs); 
   } 
 
   list = g_list_reverse (list); 
 
   return 0; 
}
~/test_qt/c$ gcc -O2 `pkg-config --cflags --libs glib-2.0` a.c
~/test_qt/c$ pkg-config --cflags --libs glib-2.0
-I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include  -lglib-2.0

Тестирование (1 000 000) элементов:

namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m0.176s
user    0m0.110s
sys     0m0.050s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m0.244s
user    0m0.060s
sys     0m0.040s
namezys ★★★★
()
Ответ на: комментарий от MuZHiK-2

Не забыл что C++ еще выделенную память в конце чистит? Удали все элементы из GList, увидешь что время выполнения сравняется.

anonymous
()
Ответ на: комментарий от namezys

> list.append( person(dendy, i) );

все правильно - ушло лишнее копирование и стало быстрее, и да - в варианте MuZHiK-2 надо еще 1000000 раз g_free вызвать + g_slice_free

ahonimous
()
Ответ на: комментарий от namezys

Добавил удаление в glib, увеличил кол-во элементов до 10 000 000

glib: 2.4s в среднем за 10 запусков (в сторону уменьшения) qt: 1.6s

namezys ★★★★
()
Ответ на: комментарий от ahonimous

Там не только линейное копирование - там еще вообще-то еще и приведение к unicode

хотя компилятор мог это и оптимизировать

namezys ★★★★
()
Ответ на: комментарий от MuZHiK-2
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.622s
user    0m1.320s
sys     0m0.300s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.802s
user    0m1.560s
sys     0m0.240s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.714s
user    0m1.370s
sys     0m0.320s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.688s
user    0m1.310s
sys     0m0.370s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.536s
user    0m1.300s
sys     0m0.190s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.637s
user    0m1.330s
sys     0m0.280s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.597s
user    0m1.210s
sys     0m0.330s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.738s
user    0m1.410s
sys     0m0.300s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.418s
user    0m1.120s
sys     0m0.290s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.354s
user    0m1.060s
sys     0m0.280s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.361s
user    0m1.050s
sys     0m0.300s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.813s
user    0m1.470s
sys     0m0.340s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.672s
user    0m1.160s
sys     0m0.210s
namezys@namezys-desktop:~/test_qt$ time qt/qt 

real    0m1.722s
user    0m1.040s
sys     0m0.200s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.493s
user    0m1.620s
sys     0m0.580s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.332s
user    0m1.350s
sys     0m0.510s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.591s
user    0m1.500s
sys     0m0.640s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.182s
user    0m1.580s
sys     0m0.440s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.511s
user    0m1.540s
sys     0m0.600s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.382s
user    0m1.750s
sys     0m0.590s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.498s
user    0m1.710s
sys     0m0.670s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.344s
user    0m1.230s
sys     0m0.590s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.426s
user    0m1.750s
sys     0m0.650s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.435s
user    0m1.880s
sys     0m0.510s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.289s
user    0m1.620s
sys     0m0.620s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.471s
user    0m1.690s
sys     0m0.610s
namezys@namezys-desktop:~/test_qt$ time c/a.out 

real    0m2.406s
user    0m1.750s
sys     0m0.640s
namezys ★★★★
()
Ответ на: комментарий от ahonimous
#include <string>
#include <list>

struct person 
{ 
    std::string nick; 
    int id; 
}; 
 
int main(int argc, char *argv[]) 
{ 
    std::list<person> list; 
    list.resize( 100000 );
    
    std::list<person>::iterator it = list.begin();
    for( int i = 0 ; i < 100000 ; ++i, ++it )
    {
    	(*it).nick = "Dendy";
    	(*it).id   = i;
    }
} 

у меня этот вариант в 8 раз быстрее варианта мужика, без очистки памяти

ahonimous
()
Ответ на: комментарий от ahonimous
#include <string>
#include <list>

struct person 
{ 
    std::string nick; 
    int id; 
}; 
 
const std::string str = "Dendy"; 
 
int main(int argc, char *argv[]) 
{ 
    std::list<person> list; 
    list.resize( 100000 );
    
    std::list<person>::iterator it = list.begin();
    for( int i = 0 ; i < 100000 ; ++i, ++it )
    {
    	(*it).nick = str;
    	(*it).id   = i;
    }
} 

если сделать как у namezys с const QString - то станет еще в 2 раза быстрее

ahonimous
()
Ответ на: комментарий от MuZHiK-2

Этот вариант на С + glib:

(-O3 -pipe -fomit-frame-pointer)
real	0m0.077s
user	0m0.039s
sys	0m0.003s

Вариант на CL:

(defstruct person (nick "") (id 0))

(defun foo (persons)
  (dotimes (i 100000)
    (push (make-person :nick "oh-no!" :id i) persons)))

(time (foo nil))
Evaluation took:
  0.013 seconds of real time
  0.007000 seconds of total run time (0.003000 user, 0.004000 system)
  53.85% CPU
  32,868,423 processor cycles
  2,402,008 bytes consed

Но чтобы быть честным я ещё объявлю типы и буду использовать append:

(defstruct person
  (nick "" :type string)
  (id   0  :type fixnum))

(defun foo (persons)
  (declaim (type list persons))
  (dotimes (i 100000)
    (setf persons (list* persons (make-person :nick "oh-no!" :id i)))))

(time (foo nil))
Evaluation took:
  0.012 seconds of real time
  0.005999 seconds of total run time (0.004999 user, 0.001000 system)
  42.86% CPU
  36,249,397 processor cycles
  2,397,912 bytes consed
quasimoto ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.