LINUX.ORG.RU

Подскажите ЯП с норм тредами

 , , ,


0

0

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

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

Думал что потоки мне помогут, но как оказалось нет. С увеличением количества потоков время на ввод почти не уменьшалось

В комментах к сему посту прочитал что сколько бы я тредов не сделал они все равно будут выполнятся на одном ядре (как в питоне так и в руби).

Посему вопрос: что делать дальше? Вижу несколько вариантов

  • переписать часть которая отвечает за ввод данных на ЯП в котором все ок с тредами
  • написать (на руби (потому что он уже используется)) небольшой сервер который будет принимать данные на морду и писать в базу. и запускать несколько копий приложений для обработки. каждое работает со своей частью данных, а результаты отдает серверу
  • тоже самое что и в предыдущем пункте но на питоне. потому что портаж на питоне и мне в любом случае будет нужно его API

Или есть другие варианты? а может я гдето сделал ошибку в моем коде?

★★★★★

http://yehudakatz.com/2010/08/14/threads-in-ruby-enough-already/

And all modern Ruby VMs that run Rails (Ruby 1.9′s YARV, Rubinius, and JRuby) use native threads, eliminating the annoying tax that you need to pay for using threads in Ruby 1.8

Это (если дядя не врет) значит, что они используют множество ядер проца, если такое доступно. Ключевое слово native threads

svu ★★★★★ ()

Совсем не очевидно, что дело в GIL. Профилировщик запускал?

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

Ключевое слово native threads

Просто для протокола - в Python они тоже native.

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

While Ruby 1.9.1 has native threads, they can't be run in parallel. Ruby and Python will both need another major breaking release to get to there.

@Joe: Yes, that's true (that only one thread runs at a time in Ruby and Python), but I don't think that either language its is on its way to ditching its global lock. Python tried and rejected fine-grained locking because all the locking/unlocking slowed down single-threaded code by 2x.

отсюда

Во-первых, информация в цитате, которую Вы приводите, устарела. Текущий стабильный релиз (1.9.1) уже не использует userspace threads. Используются нативные потоки. Хотя все равно присутсвует GIL.

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

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

насчет 1.9.1 прекрасно написано в комментариях вот тут, они не параллелятся blog.reverberate.org/2009/01/31/ruby-191-released/

разница в 1.9.1 и 1.8 заключается в том, что треды стали нативными, это повлияло и на возможности, и на скорость, но никак не решило задачу параллельности

As you know, YARV support native thread. It means that you can run each Ruby thread on each native thread concurrently.

It doesn't mean that every Ruby thread runs in parallel. YARV has global VM lock (global interpreter lock) which only one running Ruby thread has.

Опять же я не видел чтобы 2 ядро было всегда на 100% загружено потоками когда гонял тесты

Даже если в Rubinius/JRuby действительно все ОК, я все равно не хочу их использовать, так как я отдаляюсь от того что мне нужно (питон)

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

каюсь, нет. сейчас нету возможности запустить. дома попробую.

ps: смущает одна фигня. в логах тред который получает первое значение отрабатывет последним

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

Я мало знаю о sqlite, но, IIRC, он лочит базу при исполнении INSERT. Если это так, то, сколько бы Ъ-параллельных нитей ты не бросил на вставку, она не ускорится. Твой единственный шанс на ускорение - если нити выполняют долгую обработку данных перед вставкой, тогда проблему решает multirocessing.

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

все insert/update выполняются в отдельном одном треде. «плохо работают» группа тредов которая готовит данные для вставки в базу

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

«плохо работают» группа тредов которая готовит данные для вставки в базу

Тогда multiprocessing без вариантов.

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

«плохо работают» группа тредов которая готовит данные для вставки в базу

Тогда multiprocessing без вариантов.

tailgunner ★★★★★ ()

rubinius или jruby

rubinius или jruby

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

...но, конечно, если у тебя задача выполняется 2 часа, тебе нужно думать не о распараллеливании, а о земле^Wалгоритмах и структурах данных.

tailgunner ★★★★★ ()

Честно говоря, интересно =)

Но вот, не нравится добрая половина идей:

- SQLite - ну зачем брать хорошую идею и сразу её закапывать? Возможно оно и может дать какой-то прирост производительности, но если уж решили использовать Преимущества БД, то необходимо что-то серьёзное, кроме того NoSQL тут хорошо подойдёт, на мой взгляд, хотя лично у меня слишком мало опыта работы с NoSQL, что бы точно об этом сказать.

- Ruby - этот язык я почему-то не люблю ещё больше, чем питон, будет желание похоливарить - дайте знать, а пока я остановлюсь на своих предпочтениях в этом плане =) но я за переписать на любом другом языке только из-за этого.

- АПИ Portage не нужно. Конечно там много лет трудов, но новый взгляд на вещи никто не отменял, в другом случае нужно форкать Portage и править то, как он работает сейчас. Не представляю себе что-то среднее из этих 2х вариантов.

- По поводу демона, слишком непонятно, слишком абстрактно.

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

я так понимаю что твое «multiprocessing» ~= моему «запускать несколько копий приложений для обработки». только менее костыльное

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

я так понимаю что твое «multiprocessing

...это:

import multiprocessing as mp

# код пропущен для краткости

~= моему „запускать несколько копий приложений для обработки“, только менее костыльное

Ну, как Жигули ~= Мерседес.

tailgunner ★★★★★ ()

Уже сейчас ввод данных в базу занимает почти 2 часа.

У меня был эпичнейший запин с MySQL. Я парсил базу NVD (~300 МБ xml) и заносил в свою БД. На php это эпично выполнялось за (!) 6-8 часов.

Потом я написал на перле генератор sql-дампа, который из этих же 300 МБ xml делал один sql-файл размером ~100МБ. Он парсился за 10 минут.

Потом я сделал сдампил полученную БД mysqladmin-ом и полученный файл дал MySQL это на обработку. В этот раз добавилось за 1 минуту.

Анализируя дамп mysqladmin-а, я пропатчил свой перловский парсер так, что он генерировал sql за минуту и столько же MySQL парсил SQL-файл (добавил блокировки таблиц, сделал компактный вывод текста и т.п.).

Потом я все переписал на чистом ANSI C, и парсинг 300 MB xml у меня занимает 30 секунд, запись в кастомный бинарный дамп (написал свой бинарный reader/writer) ~6 секунд, чтение всего бинарного дампа ~8 секунд, еще и без утечек (прогонял в цикле по нескольку раз - память не утекала).

Вывод, который сделал я для себя: я плохо разбираюсь в MySQL и php, и надо было писать сразу на том, что я знаю - на С и на Perl. Однако, когда я написал первую версию парсера на перле, который вместо нескольких часов делал работу за пару минут вместо нескольких часов на пхп - это был настоящий праздник.

Почему я это написал? Скорее всего, ты неправильно делаешь или не делаешь вовсе LOCK TABLES, и потому запись в БД очень медленная. Потом, наверняка индексы расставлены неоптимально. Могу попробовать помочь тебе (в пределах своей компетенции), если дашь больше информации.

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

Переписать на C++ или изучить внимательнее с профилировщиком. А то помню, как один вовремя вставленный QString::reserve() ускорил запись XML-файла в 50 раз - т.к. до этого слишком часто перераспределялась память под строку при подготовке данных. Хотя напарник уже думал винить во всём якобы тормознутый Qt XML.

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

SQLite - ну зачем брать хорошую идею и сразу её закапывать? Возможно оно и может дать какой-то прирост производительности, но если уж решили использовать Преимущества БД, то необходимо что-то серьёзное, кроме того NoSQL тут хорошо подойдёт, на мой взгляд, хотя лично у меня слишком мало опыта работы с NoSQL, что бы точно об этом сказать.

portage это package manager, базовая часть системи. скажи любому гентушнику что для PM нужно тянуть mysql/mongodb и он плюнет тебе в лицо. Пример с амароком помните?

Ruby - этот язык я почему-то не люблю ещё больше, чем питон, будет желание похоливарить - дайте знать, а пока я остановлюсь на своих предпочтениях в этом плане =) но я за переписать на любом другом языке только из-за этого.

взят только для ваяния портотипа (потому как мне ближе)

АПИ Portage не нужно. Конечно там много лет трудов, но новый взгляд на вещи никто не отменял, в другом случае нужно форкать Portage и править то, как он работает сейчас. Не представляю себе что-то среднее из этих 2х вариантов.

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

По поводу демона, слишком непонятно, слишком абстрактно.

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

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

проблема не базе и не в работе с ней. а том что данные для записи в базу медленнно/неоптимально обрабатываются.

Я парсил базу NVD (~300 МБ xml) и заносил в свою БД. На php это эпично выполнялось за (!) 6-8 часов.

Потом я написал на перле генератор sql-дампа, который из этих же 300 МБ xml делал один sql-файл размером ~100МБ. Он парсился за 10 минут.

Потом я сделал сдампил полученную БД mysqladmin-ом и полученный файл дал MySQL это на обработку. В этот раз добавилось за 1 минуту.

Анализируя дамп mysqladmin-а, я пропатчил свой перловский парсер так, что он генерировал sql за минуту и столько же MySQL парсил SQL-файл (добавил блокировки таблиц, сделал компактный вывод текста и т.п.).

это все круто и все такое. но у меня исходные данные лежат разбросаны в разных частях 30к мелких файлов (ебилды из гентушного портажа). Плюс иногда я не могу распарсить эти данные потому что там есть строки вида

IUSE="${IUSE_A} $IUSE_B"

в таком случае я вызываю внешнюю программу (из пакета portage) которая дабавляет нехилые задержки

ZuBB ★★★★★ ()

Надо было сразу писать на Хаскелле. Единственный язык с нормальной параллелизацией и вменяемой конкурентностью.

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

сори. с первого раза не врубился что вы написали. «переезд» на другой ЯП - это вариант, который я оставлю на десерт

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

но у меня исходные данные лежат разбросаны в разных частях 30к мелких файлов (ебилды из гентушного портажа). Плюс иногда я не могу распарсить эти данные потому что там есть строки вида

Причем здесь это? Ты говоришь, что медленно происходит INSERT INTO .... Я тебе дал пример того, как этот INSERT ускорить.

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

У меня был эпичнейший запин с MySQL. Я парсил базу NVD (~300 МБ xml) и заносил в свою БД. На php это эпично выполнялось за (!) 6-8 часов.

Потому что фиксировал транзакцию для каждого INSERT?

Потом я написал на перле генератор sql-дампа, который из этих же 300 МБ xml делал один sql-файл размером ~100МБ. Он парсился за 10 минут.

Потому что валил в базу всё в рамках одной транзакции?

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

Скорее всего, именно так.

Повторюсь, я не знаток реляционных БД, но для себя решение проблемы нашел.

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

Тем паче, ситуация ТСа очень смахивает на мою.

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

Повторюсь, я не знаток реляционных БД, но для себя решение проблемы нашел.

Если мое предположение верно, твое решение не имело никакого отношения к смене инструмента (ну то есть вообще никакого). И ты не «ускорил INSERT» - ты выполнил вместо него что-нибудь вроде bulk load.

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

Что ты хочешь этим сказать? Что ты лучше меня разбираешься в базах данных? Возможно. И что дальше? У меня была проблема (медленная обработка), я ее решил (обработка стала быстрой). Я не силен в матчасти, но ведь проблема решена.

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

Что ты хочешь этим сказать?

Что вот эта фраза:

bk_> надо было писать сразу на том, что я знаю - на С и на Perl

неверна. Тебе нужно было учить матчасть.

меня была проблема (медленная обработка), я ее решил (обработка стала быстрой)

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

tailgunner ★★★★★ ()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

неверна. Тебе нужно было учить матчасть.

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

Но твое решение сводится к генерации дампа и массовой загрузке (не факт, что это подходит ТС, хотя всё может быть), а не к выбору инструментов.

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

bk_ ★★ ()

Уже сейчас ввод данных в базу занимает почти 2 часа

Дай угадаю, делаешь кучу инсертов отдельными транзакциями?
Вот здесь написано почему так и что делать: https://www.sqlite.org/faq.html#q19
Мог бы и сам нагуглить. Треды и GIL тут совсем не причём, да.

anonymous ()

Не смог удержаться

На ЛОРе самые хорошие треды получаются у хаскелла с общелиспом.

Virtuos86 ★★★★★ ()

Сорри, если я напишу ваще не в тему, но вот вариант: однажды я писал на руби скрипт, который собирал и клал в базу много-много данных, десятки миллионов. База была Postgresql, скрипт работал минут 40 и всё было уныло. Поэтому я сделал так: разделил процесс на две части: вместо собирания и складывая с базу я написал собирание и запись в CSV файл. А во второй части я импортировал CSV средствами Postgres'a во временную таблицу. Ну а уже потом сложным запросом из временной складывал в нормальную, по пути преобразовывая данные. В итоге время сократилось с 40 минут до 50 секунд. Не пригодится история - забей, пригодится - хорошо :)

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

Единственный язык с нормальной параллелизацией и вменяемой конкурентностью

Единственный

Ребятам, пищущим эрланг, не говорите.

buddhist ★★★★★ ()

Расскажи для общего развития чем руби приглянулся?

true_admin ★★★★★ ()

начинай пилить и велосипедить golang к моменту появления его в требуется быть тебе гуру.

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

Ребятам, пищущим эрланг, не говорите.

не скажем :)

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

на работе нужно было «вот и приглянулся»

очень приятный, гибкий в разработке.

до руби не сталкивался со скриптовыми яп (только js, но он какбы веб онли; нода появилась после того как я слез с js)

ты наверное был бы рад услишасть сравнение с питоном, но к сожалению опыта питона уж совсем мало..

здесь такой себе тред. мож тебе будет интересно.

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

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

true_admin ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.