Метатабличный / Говнокод #24031 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
local buff = ""
for line in io.lines() do
     buff = buff .. line .. "\n"
end

Несмотря на его безобидный вид, этот код может сильно ударить по быстродействию для больших файлов:
например, чтение файла размером 1 Мб занимает 1,5 минуты

Запостил: 3oJIoTou_xyu 3oJIoTou_xyu, (Updated )

Комментарии (90) RSS

  • Полагаю что прошлый buff остается в куче, и в ней же создается новый из buff + строка из файла

    хуй
    хуйхуй
    хуйхуйхуй
    хуйхуйхуйхуй

    итд

    Прежде чем GC его заберет у тебя будет тратиться память.

    В жабах и CLR для этого есть StringBuilderы
    Ответить
    • Причем тут память? В вашем ПТУ вычислительную сложность не проходили?
      Ответить
      • Нам трудовик в ПТУ рассказывал что память тут при том, что каждый раз придется копировать все больше и больше данных, а потом еще и GC включица.

        Погугли "Shlemiel the painter’s algorithm"
        Ответить
        • Мне больше нравится публикация на русском в виде анекдота.

          Шлемиль устроился на работу маляром и должен был наносить разметку посредине дороrи. В первый день он взял бочку краски и разметил 300 метров дороrи.
          -Неплохо! - сказал босс - Ты быстро работаешь! - И заплатил ему денежку.
          На следующий день Шлемиль осилил только 150 метров.
          - Ну что ж, не так здорово, как вчера, но ты все равно быcrpо работаешь. 150 метров это не мало, - сказал босс и заплатил ему денежку. Еще через день Шлемиль расчертил 30 метров дороrи.
          Bcero 30 метров! - рассвирепел босс - Это никуда не годится. В первый день ты сделал в десять раз больше. Что случилось?
          - Ничеrо не могу поделать, - говорит Шлемиль. С каждым днем приходится все дальше и дальше уходить от бочки с краской..
          Ответить
        • Проблема не в, как ты пишешь, "Прежде чем GC его заберет у тебя будет тратиться память.", а в том, что тебе каждый раз придется копировать все что было, что в итоге даёт O(n^2).
          Ответить
          • Да, ты прав: возврастает время на копирование потому что данных становица больше.
            Возможно еще придется находить длину строки. Я не знаю как Lua ее хранит: если строки там null terminated то каждый вызов у нас будет иметь O(длина строки), и тогда будет еще хуже.
            Ответить
  • чортов тролль! это же пример из PIL (равно как и твой пример с оператором сисек)
    11.6 String Buffers
    Suppose you are building a string piecemeal, for instance reading a file line by
    line. Your typical code would look like this:
    local buff = ""
    for line in io.lines() do
    buff = buff .. line .. "\n"
    end
    Despite its innocent look, this code in Lua can cause a huge performance penalty
    for large files: for instance, it takes 1.5 minutes to read a 1 MB file on my old
    Pentium machine.1
    Ответить
  • блядь
    почему
    a = {"a", "b", "c"}
    table.concat(a, ",") --a,b,c
    a:concat(",") --не работает???
    Ответить
    • A call v:name(args) is syntactic sugar for v.name(v,args), except that v is evaluated only once.

      a.concat(a, ",") тоже не работает.
      table.concat(a, ",") почему-то работает.
      Ответить
      • А вот в "PHP" всё предсказуемо и объясняемо.
        Ответить
      • table:concat(",") работает (и, естественно, выдаёт пустую строку).

        Почему-то именно a.concat(a, ",") и синтаксический сахар a:concat(",") не хотят захватывать значение a.
        Ответить
            • Переведи на "PHP", и, возможно, я смогу вам помочь.
              Ответить
          • b=table
            b.concat(a, ",") работает.
            b=a
            b.concat(a, ",") не работает.
            Ответить
            • Похоже что мембера "concat" нету у отдельно взятой таблицы. В модуле table такой метод есть, а в таблице нет.
              Ответить
              • Даже так работает:
                rawget(table,"concat")(a,",")
                А так не работает:
                rawget(a,"concat")(a,",")

                То есть конструктор {} не добавляет к таблице методы.
                Ответить
                • да-с
                  хуйня-с

                  вот у строки есть
                  a = ""
                  a.find --function
                  
                  а у таблы нема
                  a = {}
                  a.concat --nill

                  ташто в table.concat table это модуль(сиречь таблица) а не тип.

                  Вооще говоря противно конечно, почти так же противно как тот факт што
                  ``"A".find`` это синт ошибка, а
                  a = ""
                  a.find --это функция

                  Lua непредскаузем, как C++:)
                  Ответить
                  • Починил же. Нужно в конструкторе писа́ть:
                    a = {"a", "b", "c", concat = table.concat}
                    Тогда всё будет работать.
                    Ответить
                    • нещитово, бо так можно любую функцию в любую таблицу запиахть

                      petuh = {1, 2, 3, ["len_2"] = function(t) return #t * 2 end}
                      
                      print(petuh:len_2())


                      даже твой пример можно переписать так
                      petuh = {1, 2, 3, ["hujat"] = table.concat}
                      
                      print(petuh:hujat(","))
                      Ответить
                      • Оказывается, можно было проще:
                        setmetatable(a, table)

                        Тогда всё работает.
                        Ответить
                        • он типа метатейблу своему делегирует вызовы которые сам не умеет?)

                          лол, этоже прототи наследованне (я еще до ООП не дочитал)
                          Ответить
                        • лгун
                          tbl = {1,2,3}
                          
                          setmetatable(tbl, table)
                          
                          print(tbl:concat(","))

                          lua: attempt to call method 'concat' (a nil value)


                          metatableу делегируются вызовы неизветсных методов, вставки, получения длины итд, но только надо это явно сообшщить
                          Ответить
                          • Только что работало. Перезапустил интерпретатор, теперь не работает. Значит, я чем-то засрал контекст в прошлый раз.
                            Ответить
                            • попробуй перезагрузиться
                              три раза

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

                              tbl = {1,2,3}
                              
                              meta = { 
                               __index = function(tb, i)
                                 return i * 2 --тут tb -- это табла а i это индекс
                               end
                              }
                              
                              tbl = setmetatable(tbl, meta)
                              print(tbl[1]) --1
                              print(tbl[100500]) --201000


                              Вероятно можно это как-то обыграть
                              Ответить
                              • Обыграл метатаблицу, проверь:
                                a={1,2,3}
                                
                                meta = { 
                                 __index = function(tb, i)
                                   return rawget(table, i)
                                 end
                                }
                                
                                setmetatable(a,meta)
                                
                                print(a:concat(","))


                                Делаем так, чтобы метод __index искал методы не в нашей таблице, а в table.
                                Ответить
                                • И для конкатенации есть метаметод __concat который прекрасно подойдет для table.concat
                                  Ответить
                              • Если я правильно понял:

                                1. У типов table и userdata создаётся своя метатаблица на каждый экземпляр, поэтому её придётся привязывать после каждого вызова конструктора.

                                2. У строковых и числовых типов метатаблица одна на класс.

                                3. Для строк уже создана метатаблица, а поскольку она одна на весь класс строк, то moyastroka:format работает.

                                4. Парсер — лох, поэтому "петух":format не работает. Приходится литерал сохранять во временной переменной.

                                5. Переменная table — это такая „таблица“, не содержащая данных, но содержащая методы, поэтому table.concat работает.
                                Ответить
                                • С табле легко метатаблу привязать. А юзердата луа не может никак работать, так как это прилетающая хуета из си, дописывать интерплиттор только.

                                  И к коду выше. Зачем мучаться каждый раз привязывать метатаблицу к таблице, заебешься когда у тебя будет 100500 таблиц и придеться явно каждый раз привязывать данную метатаблицу.
                                  Можно юзнуть метаметод __newindex у _G, главное в рекурсию не улететь. И когда мы будет создавать глобаль уже будет автоматом таблице привязавоться метатаблица с методом __index с той самой библой table.
                                  С локалями данный метод не работает так как локали не создаются в _G а где-то в другом месте. Пока сам не знаю где, не доходило дело и до них.
                                  Ответить
                                • У строки по моему нельзя привязать метатаблицу если отключен (или включен) дебаг.
                                  Ответить
                                • > Парсер — лох, поэтому "петух":format не работает. Приходится литерал сохранять во временной переменной.
                                  Зойчем зосорять просранство имён?
                                  ("питух"):format
                                  Ответить
                                  • >>Зойчем зосорять просранство имён?

                                    незасорил пространство имен, проверьт
                                    tbl = {}
                                    
                                    do 
                                      local foo = {__index = function() return 42 end}
                                      setmetatable(tbl, foo)
                                    end
                                    
                                    print(foo) --будет nil
                                    print(tbl[100400]) --будеьт 42
                                    Ответить
                                        • collectgarbage = nil
                                          Ну теперь точно ничего не сделает, потерял ссылку на сам сборщик.
                                          Добро пожаловать утечка
                                          Ответить
                                        • конечно не сделает

                                          foo зажат у setmetatable между булками

                                          В луа же так идеома итератора работает
                                          function Spam()
                                            local i = 0 --i снаружи не видать
                                            return function() if i < 42 then return 1 else return nil end
                                          end
                                          
                                          for i in Spam() do 
                                            print(i)
                                          end
                                          Ответить
                                          • Так когда он вышел за границы блока он же тупо теряет ссылку к значению, но само значение валяеться и тухнет. К тому же был случай, когда запускаешь сборщик мусора в поток параленьно работающей функцией у которой кучи локалей, и ждешь когда что наебнеться
                                            Ответить
                                            • >>, но само значение валяеться и тухнет
                                              так гц же

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

                                              Я знаю только про корутины которые работают в одном треде операционки.

                                              Разве в луа есть какие-то другие треды?

                                              Что будет если у меня переменная указывает на объект, который забрал гц? Может так быть? Если да, то что будет? nil?
                                              Ответить
                                              • В чистом луа - нет.
                                                Нет не нил, а помоему вывалится с ошибкой. НО ВСЕ ЭТО НИТОЧНО, НАДО БОЛЬШЕ ИСЛЕДОВАНИЙ, я давно с этим баловался
                                                Ответить
                                                • а, ну понятно: если host каким-то образом зачистил что-то на что есть ссылка то может быть что угодно

                                                  гарантировать патокабизопастность должен host, в который встроен lua

                                                  сам lua для этого средств не имеет
                                                  Ответить
                                • >> userdata создаётся своя метатаблица на каждый экземпляр, поэтому её придётся привязывать после каждого вызова конструктора.
                                  Пиздешь.
                                  file = io.open("petux.txt","r")
                                  file:close()
                                  Ответить
                    • Даже так:
                      a = {"a", "b", "c",
                      concat = table.concat,
                      insert = table.insert,
                      move = table.move,
                      pack = table.pack,
                      remove = table.remove,
                      sort = table.sort,
                      unpack = table.unpack}

                      Ничего не забыл?
                      Ответить
                      • ого, я чото не знал что

                        foo = {["spam"] = 42}
                        можно записать как
                        foo = {spam = 42}

                        Что то есть неуловимое от старого JSа где объект есть массив ассоциативный
                        Ответить
              • a.concat = table.concat
                a:concat(",") -- теперь работает
                Ответить
  • Почему в питоне есть мутабельная байтовая строка bytearray, но нету юникодной?

    В питоне такой код пишут часто и всем похуй. Пока не понадобится запустить его на жытоне, например.
    Ответить
    • В Питонии строки имутабельны, bytearray - это не строка, а массив байт.
      >>> a = bytearray("хуй", "utf-8")
      >>> a
      bytearray(b'\xd1\x85\xd1\x83\xd0\xb9')
      >>> a[0] = 33
      >>> a
      bytearray(b'!\x85\xd1\x83\xd0\xb9')

      Жытон - это Jython? Я на нём ни разу не писал, ты о чём?
      Ответить
      • Как сказанное тобой относится к моему посту? Я спросил почему нету такого же для юникода.

        Для жытона модули кто пишет?
        Ответить
        • > нету такого же для юникода
          Я не понял, ты хочешь мутабельную уникодную сьроку?
          s = somefuckinshit("хай")
          s[1] = "у"
          ???
          Ответить
          • >Почему в питоне есть мутабельная байтовая строка bytearray, но нету юникодной?
            А ты доходчивый.
            Ответить
            • Попытаюсь предположить.

              Легко сделать мутабельность для строки, у которой представление символа имеет фиксированный размер: для байтового массива, для восьмибитных кодировок, для UCS-2 (строго 16 бит = 2 байта на символ), для UCS-4 (строго 32 бита = 4 байта на символ).

              Трудно сделать мутабельность для строки, символ которой имеет переменный размер (для UTF-8 и прочих MBCS). Почему? Потому что при изменении единственного символа строки может измениться длина байтового представления. Разработчики испугались трудностей.

              Вернёмся к примеру:
              s = somefuckinshit("хай")
              s[1] = "у"

              Если s в UTF-8, то, во-первых, для поиска s[1] придётся просканировать всю строку до интересующего индекса, ведь заранее нельзя угадать, сколько байт занимают предыдующие буквы. В данном случае требуется узнать, сколько байт займёт буква "х". Во-вторых, если будем заменять "а" на "у", то всё хорошо, а если попытаемся заменить на латинскую букву (которая в UTF-8 занимает меньше места), то придётся сдвигать на 1 байт весь остаток строки.

              Можно для пирфоманса внутри хранить строку в UCS-4 (4 байта на символ), а преобразовывать в utf-8 только при вводе-выводе, но тогда хранение строк будет жрать больше памяти.
              Ответить
              • Там не utf-8, иначе индекс был бы за O(позиция)
                Ответить
              • Ну и что мешает сделать мутабельную строку UTf-8? Ну пускай там будет поиск не O(1) а O(N). Если ты в скриптовом язычке то тебе должно же быть пофиг, не?

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

                Потому что строки имеют дурную привычку быть инициализированными строковыми литералами, и у тебя 100500 строк, которые все указывают на строчку "pitux" где-то в коде, и когда ты хочешь поменять один символ тебе придетца делать CopyOnWrite со всеми вытекаюшими.

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

                  мутабельность строк имеет ровно одну проблему - ее нельзя будет использовать в качестве ключа в словаре, но тебе это и так никто не даст.
                  Ответить
                  • А руби строки мутабельные, и всем опхуй.

                    Для ключей они, разумеется, не подходят: нужны символы
                    Ответить
      • Матапушта в питоне bytearray и был создан для этого, как я понимаю. А вот юникодный забыли.
        Ответить
        • Хоть бутеаррау, хоть строки при конкатенации всё равно придёться realloc'ать и копировать данные.
          Ответить
            • Луркнул тебе за сфинктер - да убери ты, убери свои лапы!
              Ненавижу, когда пассы руками лезут куда не просят. во время ёбли.
              Ответить
            • Ну он примерно так и работает:
              1) выделает N памяти
              2) если место кончается -- делает realloc.
              Ответить
              • > при конкатенации всё равно придёться realloc'ать и копировать данные.
                > если место кончается -- делает realloc.
                Чувствуешь разницу?
                Ответить
          • Заварил доширак, добавил майонез и повесил тебе на уши - а ля пейсы, проверь.
            Ответить
            • Заварил доширак дождевой водой в медном тазу, добавил майонез из павлиньих яиц и кунжутного масла, украсил сушёными лягушками. Рекомендовал как средство от холеры.
              Ответить
  • Конкатенация двумя точками??? Ахаха, ебать вы оригинальны.
    Ответить

Добавить комментарий

Из-за тебя ушел bormand, guest!

    А не использовать ли нам bbcode?


    8