Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Ускорить обработку массива
 
 автор: Владимир55   (20.01.2012 в 19:59)   письмо автору
 
 

Из массива удаляются элементы, не содержащие образца, и делается это перебором
<?php
for ($i=0$i $n_zap$i++) if (!stristr ($m_zap[$i], $slovo)) unset($m_zap[$i]);


Для ускорения быстродействия желательно выполнить эту операцию через array_map, создав для этого соответствующую функцию.
<?php
    
function selekt($m_zap){
        if (!
stristr ($m_zap$slovo)) unset($m_zap);
    }
    
$m_zap array_map("selekt"$m_zap);


Такое возможно?

  Ответить  
 
 автор: cheops   (21.01.2012 в 12:19)   письмо автору
 
   для: Владимир55   (20.01.2012 в 19:59)
 

Дело в том, что функция обратного вызова у вас возвращает значение, которое присваивается элементу массива... вероятно придется все-таки использовать первый вариант. А насколько остро стоит проблема быстродействия? Может тогда не удалять элементы по одному, а просто сформировать новый массив, а старый удалить при помощи одного вызова unset()?

  Ответить  
 
 автор: Владимир55   (21.01.2012 в 12:28)   письмо автору
 
   для: cheops   (21.01.2012 в 12:19)
 

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

Если удалить элемент массива не возможно, то, может быть, в него можно записать нулевое значение? Или какой-нибудь служебный знак?

  Ответить  
 
 автор: cheops   (21.01.2012 в 12:34)   письмо автору
 
   для: Владимир55   (21.01.2012 в 12:28)
 

Понимаете какая штука, вы когда удаляете элемент - это дорогая операция (без разницы, что вы удаляете 1 элемент или 1 массив), если это сделать 20 000 раз вместо одного - скорости это вам не прибавит. Лучше, если есть память, сформировать параллельно еще один массив без элементов, а старый удалить - это будет всех быстрее (ну если, конечно, памяти достаточно и программа не свалится в swap).

PS Какой средний объем строки? У меня при среднем объеме в 256 байт получилось пол гигабайта памяти... может эту операцию разумнее в базе данных провести (она на порядки быстрее будет работать, чем PHP-скрипт)?

  Ответить  
 
 автор: Владимир55   (21.01.2012 в 12:42)   письмо автору
 
   для: cheops   (21.01.2012 в 12:34)
 

Исходная информация хранится в тестовом файле размером четыре гигабайта. Я преобразую её в массив для обработки строк.

Разумеется, такой объем в скрипт не загнать, так что придется исходный текствовый файл делить на части и вызывать скрипт несколько раз. Но все равно, набо бы побыстроее, ибо делить на 10 частей - это одно, а на пятьдесят частей - это уж слишком долго.

Работа на Денвере.

  Ответить  
 
 автор: Владимир55   (21.01.2012 в 12:36)   письмо автору
 
   для: Владимир55   (21.01.2012 в 12:28)
 

Может тогда не удалять элементы по одному, а просто сформировать новый массив, а старый удалить при помощи одного вызова unset()?

Вы имеете в виду, что оператором array_map из массива $m_zap формируется массив $m_zap_new, все элементы которого удовлетворяют условию?

Пожалуй, что это даже лучьше!

А как это сделать?

  Ответить  
 
 автор: cheops   (21.01.2012 в 12:54)   письмо автору
 
   для: Владимир55   (21.01.2012 в 12:36)
 

>Вы имеете в виду, что оператором array_map
Да вообще без array_map(), там все-равно идет вызов PHP-функции, а это медленно. Просто последовательно наращивайте новый массив и записывайте потом результат. Смысл в том, что добавление новых данных без разрывов идет быстрее, чем их удаление из середины.

PS Вообще, конечно, лучше бы эту задачу вообще на C++ решать - там и скорость и полный контроль над памятью (но составление программы, конечно, более трудоемкое занятие).

  Ответить  
 
 автор: Владимир55   (21.01.2012 в 13:13)   письмо автору
 
   для: cheops   (21.01.2012 в 12:54)
 

Вообще, конечно, лучше бы эту задачу вообще на C++ решать

Всё больше понимаю, что С++ - это сказка! В том смысле, что предоставляет фантастические возможности!

  Ответить  
 
 автор: cheops   (21.01.2012 в 13:27)   письмо автору
 
   для: Владимир55   (21.01.2012 в 13:13)
 

Там и трудозатраты фантастические, на то что делает один PHP-программист потребуется несколько C++-программистов или работа в течение более длительного времени или готовые наработки... Да и квалификация должна быть выше, там нельзя просто так уже туда сюда данные гонять, под которые автоматически интерпретатор выделяет память, а потом убирает за пользователем. Там все делается вручную: вычислил сколько памяти нужно, взял, использовал, вернул обратно, сам не вернешь, никто за тебя не вернет. Поэтому, когда получили распространение сервера, утечка памяти приобрела масштаб стихийного бедствия - сервер стартует с 1ГБ, через неделю глянешь - он 2 ест... перезагрузка серверов ничего не дает, нужно машину перезагружать... Даже опытный программист где-то да забудет вернуть ресурсы системе. В PHP и вообще современных языках эта проблема решена как класс... ну как решена, осталась, конечно, но ей занимаются системные программисты, те, кто PHP-интерпретатор пишет, по крайней мере с прикладного уровня её удалось убрать. Вот когда берется C++ в руки, с этой проблемой приходиться сталкиваться... так мало того, что память течет - черт бы с ней, особенно, в программах которые быстро закрываются, ошибки ослабляют проблемы безопасности... Поэтому новые C++ проекты очень редко сейчас стартуются, ну если только без C++ никуда... операционные системы, СУБД, игры, браузеры, торговые системы и т.п.

  Ответить  
 
 автор: Владимир55   (23.01.2012 в 10:21)   письмо автору
 
   для: cheops   (21.01.2012 в 13:27)
 

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

Тут у меня в памяти вспывают жуткие ассоциации, связанные с Фортраном. Все эти кошмарные операторы описания EXTERNAL, IMPLICIT, EQUIVALENCE, COMMON, DIMENSION... Бр-р-р...

В С++ делается похожим образом?

  Ответить  
 
 автор: cheops   (23.01.2012 в 12:23)   письмо автору
 
   для: Владимир55   (23.01.2012 в 10:21)
 

Даже покруче... если в фортране вы на этапе компиляции размер каждого из этих участков задавали, то в C++ они меняются динамически... Т.е. вы размер этих блоков сами вычисляете в программе, сами выделяете сколько вам нужно, сами следите, чтобы выделилось (может у машины памяти столько нет), потом возвращаете в систему после использования (или до, если возникла ошибка в другом месте)... а уже если на уровне операционной системы работаете, то там память можно брать в нескольких местах, можно из кучи процесса запросить, можно свою кучу организовать, а то и две, а можно прямо у операционной системы занять виртуальной памяти... А самое страшное никто не следит, за тем, что вы будете писать или читать за границами выделенного участка (ну если только он не сверхкритичен для системы), т.е. прошли мимо границы, а там дальше начинается код программы: в программе это заканчивается ошибкой, в драйвере - синим экраном смерти. Ну и понятно, это также позволяет ломать системы - т.е. вы можете читать ассемблер-код практически из любого места, а в ряде случаев подменять своим: т.е. если в базе данных SQL-инъекции, то в C++ переполнение буфера - суть примерна та же.

Кроме того в фортране, каким мы его помним, всегда был один поток, а в C++ их сейчас куча процессов, а в каждом процессе куча потоков: и все они обращаются к одним и тем же ресурсам и участкам памяти, т.е. нужно производить синхронизацию, чтобы они друг другу не мешали. Зато сами себе хозяин, можете сказать, поток который обрабатывает первый файл - на первое ядро процессора, поток, который обрабатывает второй файл - на второе ядро процессора, на третьем пусть ждет поток, который будет результаты первых двух обрабатывать, а на четвертом пусть сидит сама программа и следит за элементами управления, за которые дергает пользователь. Вот в C++ это можно было еще в 90-х делать, когда многоядерных процессоров не было, а были лишь многопроцессорные компьютеры. Когда это можно будет делать на обычных языках - большой вопрос... да и вообще скорее всего другие языки появятся под это дело (а С/C++ останется и код на нем написанный останется, тот же WinAPI).

В общем в C++ даже если вроде собрался писать прикладную программу, оглянуться не успеешь, как уже занимаешься системным программированием (т.е. и железо и операционную систему нужно знать, иначе ничего не сделаешь). Зато ваш огромный файл вы могли бы поместить в адресное пространство программы сразу одним махом, просто отразив его в адресное пространство процесса, сделав частью виртуальной памяти - быстрее способа передать содержимое файла в оперативную память нет (примерно так открываются файлы в Word, Excel, Photoshop - каждый из них готовый кусок exe-кода, который встраивается в адресное пространство, когда наступает его черед быть открытым). Все это великолепие огорчается ровном одним - операционные системы не совместимы друг с другом, если нужна переносимость, приходится пользоваться стандартными средства, а не системными вызовами. Но даже в этом случае все остается в силе, у вас просто память берется лишь из одного места - из кучи процесса, да с файлами приходится работать теми же C-функциями fopen(), fwrite(), fread() или С++-библиотеками, вроде iostream.

PS В общем Fortran это еще цветочки, он как мог держал программистов подальше от системы, EXTERNAL и COMMON - это уж, чтобы вообще не потерять скорости. Не можем мы пока позволить себе чистый академический код без срезания углов. Там в ранних версиях еще и entry-входы в процедуры были, чтобы можно было процедуру не с начала, а с середины выполнять - скорости прибавляло (это фактически адресация), а вот с точки зрения создания программ - это кошмар, понятный только тем, кто на ассемблере и C шарашит.
PPS Единственное, что в C/C++ лучше: адрес памяти - это адрес памяти, а не как в Fortran специальное ключевое слово, обозначающее участок памяти, который обладает специальными средствами и возможностями... и под каждый случай жизни - свое собственное ключевое слово.
PPPS Ну и Fortran сейчас немного другой - там избавились от фиксированного формата, ввели динамическую память, причесали мат.библиотеку (обалденного размера), операторы на привычные заменили... т.е. он сейчас на порядок приличнее выглядит, чем раньше, когда от него за версту веяло большими и нестабильными машинами с перфокартным вводом.

  Ответить  
 
 автор: Владимир55   (23.01.2012 в 12:57)   письмо автору
 
   для: cheops   (23.01.2012 в 12:23)
 

Fortran ... сейчас на порядок приличнее выглядит, чем раньше, когда от него за версту веяло большими и нестабильными машинами с перфокартным вводом.

БЭСМ-6, а также ЕС-1030, ЕС-1032, ЕС-1045 Польского производства...
И перфоленточным - СМ-2. СМ-4...

  Ответить  
 
 автор: Valleri   (23.01.2012 в 01:19)   письмо автору
 
   для: Владимир55   (20.01.2012 в 19:59)
 

Я программно сравнивал огромные файлы, построчно, в начале года.
Данные заносил в массивы и производил сравнение
Использовал функции библиотек PHP
Перепробовал почти все функции для работы с массивами.
array_search, in_array быстрее других функций из PHP работают, в моих экспериментах
http://softtime.ru/forum/read.php?id_forum=1&id_theme=80990&page=2
http://softtime.ru/forum/read.php?id_forum=1&id_theme=81351&page=2

На си не стал писать, но применил дополнительно несколько алгоритмов, ускоряющих общую работу скриптов.

  Ответить  
 
 автор: Владимир55   (23.01.2012 в 10:13)   письмо автору
 
   для: Valleri   (23.01.2012 в 01:19)
 

Не знаю, по какой причине, но у меня Денвер даже 50 Мб. закачивает в переменную не всегда, так что осуществить задуманную обработку средствами РНР не представляется возможным.

Но тут мне подфартило - нашлась программа на С++, которая с предварительной селекцией справилась и массив ужался до 35 Мб.

  Ответить  
 
 автор: cheops   (23.01.2012 в 12:26)   письмо автору
 
   для: Владимир55   (23.01.2012 в 10:13)
 

Возможно в php.ini следует увеличить объем, отводимой скрипту памяти, больше чем указано в memory_limit, загрузить не удастся.

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования