Python: s/callback/generator/
От: Roman Odaisky Украина  
Дата: 14.07.09 07:58
Оценка:
В модуле ftplib есть такая функция:
retrlines(self, cmd, callback=None) unbound ftplib.FTP method
    Retrieve data in line mode.  A new port is created for you.

    Args:
      cmd: A RETR, LIST, NLST, or MLSD command.
      callback: An optional single parameter callable that is called
                for each line with the trailing CRLF stripped.
                [default: print_line()]

    Returns:
      The response code.


Как можно передать ей такой callback, чтобы написать

def ftplines(ftp, filename):
    . . .
    callback = . . .
    ftp.retrlines("RETR " + filename, callback)

for l in ftplines(ftp, "/etc/shadow"):
    . . .

т. е., заставить результат работать как генератор?

14.07.09 17:19: Перенесено из 'Декларативное программирование'
До последнего не верил в пирамиду Лебедева.
Re: Python: s/callback/generator/
От: palm mute  
Дата: 14.07.09 08:33
Оценка: 8 (1) +1
Здравствуйте, Roman Odaisky, Вы писали:

RO>В модуле ftplib есть такая функция:

RO>...
RO>Как можно передать ей такой callback, чтобы написать
RO>т. е., заставить результат работать как генератор?

afaik, в обычном Питоне это невозможно. Это возможно в Scheme(см. continuations), Lua (см. coroutines), Stackless Python (см. tasklets + channels).
Re: Python: s/callback/generator/
От: SergH Россия  
Дата: 14.07.09 09:17
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Как можно передать ей такой callback, чтобы написать


RO>for l in ftplines(ftp, "/etc/shadow"):


Скорее всего никак. Компилятор не поймёт и не оценит. Куда ему девать возвращаемое ftplines значение?
Делай что должно, и будь что будет
Re[2]: Python: s/callback/generator/
От: palm mute  
Дата: 14.07.09 10:55
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Компилятор не поймёт и не оценит. Куда ему девать возвращаемое ftplines значение?

Принципиальной проблемы — куда девать — нет. У корутины может быть множество промежуточных результатов и один конечный. Проблема только в ограниченной семантике корутин в Питоне.
Re[3]: Python: s/callback/generator/
От: SergH Россия  
Дата: 14.07.09 11:05
Оценка:
Здравствуйте, palm mute, Вы писали:

PM>Принципиальной проблемы — куда девать — нет. У корутины может быть множество промежуточных результатов и один конечный. Проблема только в ограниченной семантике корутин в Питоне.


Принципиальной нет, но есть синтаксическая.

Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.

А yield это просто синтаксический сахар для всего этого.
Делай что должно, и будь что будет
Re: Python: s/callback/generator/
От: Mr.Cat  
Дата: 14.07.09 11:29
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:
RO>т. е., заставить результат работать как генератор?
А как в питоне с многопоточностью? Можно было бы вынести retrlines с коллбеком в один поток (он бы блокировался на ipc), а в другом сделать генератор (который бы получал от первого потока строку и разблокировал бы колллбек).
Re[2]: Python: s/callback/generator/
От: FR  
Дата: 14.07.09 12:20
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>А как в питоне с многопоточностью? Можно было бы вынести retrlines с коллбеком в один поток (он бы блокировался на ipc), а в другом сделать генератор (который бы получал от первого потока строку и разблокировал бы колллбек).


Можно, но бесполезно из-за GIL.
Re[4]: Python: s/callback/generator/
От: FR  
Дата: 14.07.09 12:23
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.


Так начиная с 2.5 yield в обе стороны работает http://www.python.org/dev/peps/pep-0342/
Re[5]: Python: s/callback/generator/
От: Roman Odaisky Украина  
Дата: 14.07.09 13:46
Оценка:
Здравствуйте, FR, Вы писали:

SH>>Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.


FR>Так начиная с 2.5 yield в обе стороны работает http://www.python.org/dev/peps/pep-0342/


Так это поможет всё-таки переделать интерфейс на коллбэках в интерфейс на генераторах?
До последнего не верил в пирамиду Лебедева.
Re[6]: Python: s/callback/generator/
От: palm mute  
Дата: 14.07.09 13:53
Оценка: +1
Здравствуйте, Roman Odaisky, Вы писали:

FR>>Так начиная с 2.5 yield в обе стороны работает http://www.python.org/dev/peps/pep-0342/


RO>Так это поможет всё-таки переделать интерфейс на коллбэках в интерфейс на генераторах?


Нет, это всего лишь позволяет организовать двусторонний обмен сообщениями между генератором и вызывающим кодом.
Re[4]: Python: s/callback/generator/
От: palm mute  
Дата: 14.07.09 14:04
Оценка: 2 (1)
Здравствуйте, SergH, Вы писали:

SH>Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.

Неполноценность питоновских генераторов в другом — ограниченность контекста одной процедурой, тем хорошо раскрыта в Lua wiki.

SH>А yield это просто синтаксический сахар для всего этого.

С вашего позволения придерусь к терминологии, т.к. тут на РСДН принятно слишком вольно обращаться с термином "синтаксический сахар". О синтаксическом сахаре можно говорить в том случае, когда есть тривиальное синтаксическое преобразование, превращающее программу с сахаром в программу без сахара. Например, for-loop тривиально преобразуется в while-loop (используя __iter__, next и StopIteration). yield — примитив языка.
Re[5]: Python: s/callback/generator/
От: SergH Россия  
Дата: 14.07.09 14:50
Оценка:
Здравствуйте, palm mute, Вы писали:

PM>Неполноценность питоновских генераторов в другом — ограниченность контекста одной процедурой, тем хорошо раскрыта в Lua wiki.


Насколько я понял, это о том же.

SH>>А yield это просто синтаксический сахар для всего этого.

PM>С вашего позволения придерусь к терминологии, т.к. тут на РСДН принятно слишком вольно обращаться с термином "синтаксический сахар". О синтаксическом сахаре можно говорить в том случае, когда есть тривиальное синтаксическое преобразование, превращающее программу с сахаром в программу без сахара. Например, for-loop тривиально преобразуется в while-loop (используя __iter__, next и StopIteration). yield — примитив языка.

Согласен, неаккуратно выразился.

Я имел ввиду, что снаружи функция, которая использует yield неотличима от функции, возвращающей итератор. Т.е. если исключить то, как генерируется последовательность, ничего нового не вводится. Компилятор обнаруживает в теле функции слово "yield" и всё понимает сам. Ну, фактически, он оборачивает функцию в корутину, но делает это незаметно, "корутина" это деталь реализации, а не понятие, которое может использовать программист.

В Lua же вытащили её наружу. В результате функцию нужно явно завернуть в корутину (если я прввильно понял текст, Lua я не знаю). И поведение корутины ни с чем другими не спутаешь.

Т.е. в Питоне более удобно решен частный случай проблемы.
Делай что должно, и будь что будет
Re[3]: Python: s/callback/generator/
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 14.07.09 15:12
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, Mr.Cat, Вы писали:


MC>>А как в питоне с многопоточностью? Можно было бы вынести retrlines с коллбеком в один поток (он бы блокировался на ipc), а в другом сделать генератор (который бы получал от первого потока строку и разблокировал бы колллбек).


FR>Можно, но бесполезно из-за GIL.


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

Кстати, GIL уже не абсолют: http://code.google.com/p/unladen-swallow/
The God is real, unless declared integer.
Re: Python: s/callback/generator/
От: neFormal Россия  
Дата: 15.07.09 08:52
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Как можно передать ей такой callback, чтобы написать


можно сделать свой итератор, назвать его ftplines
...coding for chaos...
Re[2]: Python: s/callback/generator/
От: neFormal Россия  
Дата: 15.07.09 09:01
Оценка:
Здравствуйте, neFormal, Вы писали:

RO>>Как можно передать ей такой callback, чтобы написать

F>можно сделать свой итератор, назвать его ftplines

прикольный всё таки язык
class footp:
    x = ['a', 'd', 'b', 'e', 'c']
    def __init__(self):
    self.it = iter(self.x)
    
    def retrlines(self, cable):
    try:
            cable(self.it.next())
    except StopIteration, e:
        return False
    return True

class ftplines:
    def __init__(self, f):
    self.f = f
    
    def __iter__(self):
    return self
    
    def __assign(self, x):
    self.x = x
    
    def next(self):
    if self.f.retrlines(self.__assign) == False:
        raise StopIteration
    return self.x

ftp = footp()
for l in ftplines(ftp):
    print 'sup /rsdn.dynamic/ ' + l
...coding for chaos...
Re[3]: Python: s/callback/generator/
От: c-smile Канада http://terrainformatica.com
Дата: 15.07.09 21:25
Оценка: :)
Здравствуйте, neFormal, Вы писали:

Сугубо для сравнения вот функция в TIScript которая итерирует все строки в файле path удовлетворяющих template

function linesLike( path, template )
{
  var stream = Stream.openFile(path, "rt");
  if( stream )
     return function() // returning function - generator of strings matching the template
     {
       while(true)
       {
         var line = stream.readln();
         if( typeof line != #string )
            break; // EOF, exit
         if( line like template )  
            return line; // return matching line
       }
       stream.close();
     }
}


Используем например так:

for( var line in linesLike("/some/file", "ftp://*") )
   stdout << line << "\n";
Re[4]: Python: s/callback/generator/
От: FR  
Дата: 16.07.09 02:32
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Здравствуйте, neFormal, Вы писали:


CS>Сугубо для сравнения вот функция в TIScript которая итерирует все строки в файле path удовлетворяющих template


Оно примерно также и будет в питоне тоже, вопрос был в том чтобы итерировать класс который для этого не предназначен и превратить принимаемые им callback в итератор.
Re[5]: Python: s/callback/generator/
От: c-smile Канада http://terrainformatica.com
Дата: 16.07.09 03:39
Оценка:
Здравствуйте, FR, Вы писали:

FR>Оно примерно также и будет в питоне тоже, вопрос был в том чтобы итерировать класс который для этого не предназначен и превратить принимаемые им callback в итератор.


А... ну тогда как-то так:

function linesOfResponse( cmd )
{
  var lines = [];
  function receiver(line) { lines.push(line); }

  retrlines(cmd, receiver);

  return function() { while(lines.length) return lines.shift(); }
}

for( var line in linesOfResponse( "LIST" ) )
  stdout.printf("%s\n", line);
Re[6]: Python: s/callback/generator/
От: c-smile Канада http://terrainformatica.com
Дата: 16.07.09 03:48
Оценка:
Здравствуйте, c-smile, Вы писали:

Или вообще практически в одну строку:
function linesOfResponse( cmd ) { var lines = []; 
                                  retrlines(cmd, :line: lines.push(line) ); 
                                  return lines; }

for( var line in linesOfResponse( "LIST" ) )
  stdout.printf("%s\n", line);
Re[5]: Python: s/callback/generator/
От: z00n  
Дата: 16.07.09 05:14
Оценка:
Здравствуйте, FR, Вы писали:

CS>>Сугубо для сравнения вот функция в TIScript которая итерирует все строки в файле path удовлетворяющих template


FR>Оно примерно также и будет в питоне тоже, вопрос был в том чтобы итерировать класс который для этого не предназначен и превратить принимаемые им callback в итератор.


Вот на луа с корутинами, примерно как palm mute выше писал:

-- (* lines-like.lua *)
local co = coroutine

-- (* linesLike :: str, str, callback -> thunk *)
local function linesLike(fname,pat,callback)
  return function()
    for line in io.lines(fname) do
      if line:match(pat) then callback(line) end
    end
  end
end

-- (* используем *)
for line in co.wrap(linesLike('lines-like.lua','^loc',co.yield)) do
  print('!!',line)
end



!!    local co = coroutine
!!    local function linesLike(fname,pat,callback)
Re[7]: Python: s/callback/generator/
От: palm mute  
Дата: 16.07.09 07:21
Оценка: +1
Здравствуйте, c-smile, Вы писали:

CS>Или вообще практически в одну строку:

CS>
CS>function linesOfResponse( cmd ) { var lines = []; 
CS>                                  retrlines(cmd, :line: lines.push(line) ); 
CS>                                  return lines; }

CS>for( var line in linesOfResponse( "LIST" ) )
CS>  stdout.printf("%s\n", line);
CS>


Буферизовать и отдавать по одной строке не проблема. Мне почему-то кажется, что автору темы не хотелось качать с ФТП-сервера больше, чем нужно.
Re[4]: Python: s/callback/generator/
От: neFormal Россия  
Дата: 16.07.09 10:13
Оценка: +1
Здравствуйте, c-smile, Вы писали:

CS>Сугубо для сравнения вот функция в TIScript которая итерирует все строки в файле path удовлетворяющих template


совсем не та задача..
читай из файла с колбэком.. чтобы каждая итерация дёргала кусок данных..
...coding for chaos...
Re[8]: Python: s/callback/generator/
От: c-smile Канада http://terrainformatica.com
Дата: 17.07.09 17:43
Оценка:
Здравствуйте, palm mute, Вы писали:

PM>Здравствуйте, c-smile, Вы писали:


CS>>Или вообще практически в одну строку:

CS>>
CS>>function linesOfResponse( cmd ) { var lines = []; 
CS>>                                  retrlines(cmd, :line: lines.push(line) ); 
CS>>                                  return lines; }

CS>>for( var line in linesOfResponse( "LIST" ) )
CS>>  stdout.printf("%s\n", line);
CS>>


PM>Буферизовать и отдавать по одной строке не проблема. Мне почему-то кажется, что автору темы не хотелось качать с ФТП-сервера больше, чем нужно.


Ну во первых retrlines() по своей спецификации и так читает всё. Т.е. callback будет вызван для каждой
line. А во вторых если уже говорить про суть дела то я не вижу особой разницы в написании скажем так:

retrlines("LIST", :line:{  .... = line;...  });


и так

for( var line in responselines("LIST")) {  .... = line;...  }


Разница в основном сугубо синтаксическая.

А кстати интересно бы придумать синтаксис котрый бы позволил "разворачивать" такие вызовы....

Как-то так что-ли:

for(var line in retrlines("LIST",@)) 
   { ... = line;... }


что должно спродуцировать
retrlines("LIST", 
   function(line) { .... = line;...  }
);


Правда не ясно что делать с break; внутри такого цикла ...

Хммм... что-то в этом наверное есть... или нет?
Re[9]: Python: s/callback/generator/
От: Mr.Cat  
Дата: 17.07.09 18:49
Оценка:
Здравствуйте, c-smile, Вы писали:
CS>Разница в основном сугубо синтаксическая.
Т.е. ты предлагаешь прочитать все строки в список, а потом по нему пройтись? Это очевидное решение, но оно не подходит, если строк очень много.
Re[10]: Python: s/callback/generator/
От: c-smile Канада http://terrainformatica.com
Дата: 17.07.09 19:10
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Здравствуйте, c-smile, Вы писали:

CS>>Разница в основном сугубо синтаксическая.
MC>Т.е. ты предлагаешь прочитать все строки в список, а потом по нему пройтись? Это очевидное решение, но оно не подходит, если строк очень много.

Ты ошибаешься.

Конструкция

retrlines("LIST", :line:{  .... = line;...  });


переводится на JS как

retrlines("LIST", function(line){  .... = line;...  } );


Т.е. строки читаются функцией retrlines() и отдаются в callback одна за одной.
Что есть штатный режим использования retrlines (в Python):

retrlines(self, cmd, callback=None) unbound ftplib.FTP method
Retrieve data in line mode. A new port is created for you.

Args:
cmd: A RETR, LIST, NLST, or MLSD command.
callback: An optional single parameter callable that is called
for each line with the trailing CRLF stripped.
[default: print_line()]

Returns:
The response code.


Я же просто предлагаю доработать как-то синтаксис чтобы вызов с использованием inline callback function declaration:
retrlines("LIST", 
     function(line)
     {  .... = line;...  } 
  );


*выглядел* как скажем:
for( var line in retrlines("LIST", @ ))
  {  .... = line;...  }


что сути в общем-то не меняет — сугубый синтаксический сахар. Но приятного вкуса.
Re[9]: Python: s/callback/generator/
От: palm mute  
Дата: 18.07.09 11:46
Оценка:
Здравствуйте, c-smile, Вы писали:

PM>>Буферизовать и отдавать по одной строке не проблема. Мне почему-то кажется, что автору темы не хотелось качать с ФТП-сервера больше, чем нужно.


CS>Ну во первых retrlines() по своей спецификации и так читает всё. Т.е. callback будет вызван для каждой

CS>line.

Так в том и фокус, что нормальные продолжения или корутины позволяют взять обычную функцию и превратить ее в генератор при помощи соответствующего callback'а. См. пример z00n, он решает поставленную задачу на Lua.
Re[11]: Python: s/callback/generator/
От: . Великобритания  
Дата: 18.07.09 13:24
Оценка:
c-smile wrote:

> переводится на JS как

> retrlines("LIST", function(line){ .... = line;... } );
Это всё не то. Код "for( var line in retrlines...)" привели для примера. Суть в том, что нам нужна самостоятельная сущность iterator, c которой удобнее работать.
Если код несколько сложнее, скажем что-то типа
iter = retrlines(ftp...)
l1 = iter.next()
if(l1 == 'a'):
  l2 = iter.next()
  l3 = iter.next()
  doSomething(l2, l3, iter)
else
  doSomething2(iter.next())

switch(iter.next())
...

Т.е. если нужно не просто перебирать строки, а читать их по порядку, и это происходит изнутри какого-то хитрого сложного алгоритма, то тупо переиначить код на использование callback не выйдет. А уж если нужно читать строки из нескольких итераторов сразу... брр:
iter1 = ...
iter2 = ...
try:
   doSomething(iter1.next(), iter2.next())
except StopIteration, e:
  ...

Как ты предлагаешь использовать тут callbacks?
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: Python: s/callback/generator/
От: c-smile Канада http://terrainformatica.com
Дата: 18.07.09 18:05
Оценка:
Здравствуйте, palm mute, Вы писали:

PM>Здравствуйте, c-smile, Вы писали:


PM>>>Буферизовать и отдавать по одной строке не проблема. Мне почему-то кажется, что автору темы не хотелось качать с ФТП-сервера больше, чем нужно.


CS>>Ну во первых retrlines() по своей спецификации и так читает всё. Т.е. callback будет вызван для каждой

CS>>line.

PM>Так в том и фокус, что нормальные продолжения или корутины позволяют взять обычную функцию и превратить ее в генератор при помощи соответствующего callback'а. См. пример z00n, он решает поставленную задачу на Lua.


Ну как сказать... использовать coroutine для перебора элементов некоего stream это себя не любить.

corouitine это отдельный stack. Имплементация оных (corroutines) и в Lua и в Python (generators/yield) выполнена как т.н. называемые "green" thread (a.k.a. cooperative threads, a.k.a. fibers).

В принципе green thread значительно легче чем OS thread но тем не менее это не самая простая операция.
Re[12]: Python: s/callback/generator/
От: c-smile Канада http://terrainformatica.com
Дата: 18.07.09 19:30
Оценка:
Здравствуйте, ., Вы писали:

.>c-smile wrote:


>> переводится на JS как

>> retrlines("LIST", function(line){ .... = line;... } );
.>Это всё не то. Код "for( var line in retrlines...)" привели для примера. Суть в том, что нам нужна самостоятельная сущность iterator, c которой удобнее работать.

Роман задал конкретный вопрос который можно сформулировать след. образом:

Как трансформировать delegated-iteration в inline-iteration.

Пусть iB это блок кода который нужно выполнить на каждой итерации.
Тогда логику итерации для delegated-iteration можно описать как F(iB(el))
а inline-iteration соответственно вот это (el=F(),iB(el)).

Разница между этими двумя логически эквивалентными способами итерации
состоит в структуре стека (ну или последовательности вызовов):

F(iB(el)) на стеке лежит F frame а затем iB frame.
el=F(),iB(el) — F и iB frames появляются на стеке попеременно.

.>Если код несколько сложнее, скажем что-то типа

.>
.>iter = retrlines(ftp...)
.>l1 = iter.next()
.>if(l1 == 'a'):
.>  l2 = iter.next()
.>  l3 = iter.next()
.>  doSomething(l2, l3, iter)
.>else
.>  doSomething2(iter.next())

Есть два способа:
1) переделать саму функцию retrlines чтобы действительно можно было писать вот так:
[code]
 iter = retrlines()
 l1 = iter.next()

т.е. она должна возвращать итератор (т.е. ссылку на функцию getNextValue())
а не делать итерацию на своем стеке.

либо при сохранении текущей сигнатуры retrlines использовать способ brute force (2):
загоняем retrlines в отдельный thread и подсовываем в качестве callback функцию делающую
context switch на каждой итерации. Это то что делает coroutine.wrap в LUA.
Очевидно что это не есть самый эффективный способ рвать зубы.

Что-то мне говорит что есть еще пара способов такой трансформации ... думать надо короче.


















.>switch(iter.next())

.>...
.>[/code]
.>Т.е. если нужно не просто перебирать строки, а читать их по порядку, и это происходит изнутри какого-то хитрого сложного алгоритма, то тупо переиначить код на использование callback не выйдет. А уж если нужно читать строки из нескольких итераторов сразу... брр:
.>
.>iter1 = ...
.>iter2 = ...
.>try:
.>   doSomething(iter1.next(), iter2.next())
.>except StopIteration, e:
.>  ...
.>

.>Как ты предлагаешь использовать тут callbacks?
Re[11]: Python: s/callback/generator/
От: z00n  
Дата: 18.07.09 21:41
Оценка: 54 (3)
Здравствуйте, c-smile, Вы писали:

CS>Ну как сказать... использовать coroutine для перебора элементов некоего stream это себя не любить.

Здесь начинается ваше заблуждение.

CS>corouitine это отдельный stack. Имплементация оных (corroutines) и в Lua и в Python (generators/yield) выполнена как т.н. называемые "green" thread (a.k.a. cooperative threads, a.k.a. fibers).

CS>В принципе green thread значительно легче чем OS thread но тем не менее это не самая простая операция.
Еrlang, Lua, Stackless Python, Limbo и.т.д используют VM threads — они очень дешевые ~600-1000 байт на поток, а скорость переключения контекста соизмерима со скоростью вызова функции. Хорошая реализация продолжений (как в Chez) будет не хуже.
Т.е. для луа цена вопроса: создание потока — ~300 ns, переключение ~100ns + 1K на стек (ns — это 10e-9 sec). Stackless по моим замерам аналогичен по скорости. Limbo в пару раз быстрее, но он статически типизирован.

По поводу структурирования программ посредством микропотоков и передачи сообщений — есть интересная лекция того самого Роба Пайка. Сейчас он работает в Google — разрабатывает для них секретный язык Sawzall. Речь там идет о предтече Limbo, языке Newsqueak.

Video: Advanced Topics in Programming Languages: Concurrency/message passing Newsqueak by Pob Pike

PDF: The Implementation of Newsqueak
Re[13]: Python: s/callback/generator/
От: . Великобритания  
Дата: 18.07.09 22:49
Оценка:
c-smile wrote:

> Роман задал конкретный вопрос который можно сформулировать след. образом:

>
> Как трансформировать delegated-iteration в inline-iteration.
Ладно, может я не так понял. Но если это правда об этом, т.е. синтаксическое "преобразование", то неинтересно. А вот когда кто-то упомянул корутины — стало интересней.

> загоняем retrlines в отдельный thread и подсовываем в качестве callback

> функцию делающую
> context switch на каждой итерации. Это то что делает coroutine.wrap в LUA.
> Очевидно что это не есть самый эффективный способ рвать зубы.
Как я понимаю, в LUA корутины использую cooperative threads, что сильно упрощает жизнь — не надо использовать локи, нет никакого параллельного выполнения, системных вызовов. Просто переключаются стеки, context не такой страшный — если я правильно понимаю — указатель на текущий стек. А в более других языках это делается ещё проще.
Posted via RSDN NNTP Server 2.1 beta
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[12]: Python: s/callback/generator/
От: c-smile Канада http://terrainformatica.com
Дата: 19.07.09 06:55
Оценка:
Здравствуйте, z00n, Вы писали:

Z>Здравствуйте, c-smile, Вы писали:


CS>>Ну как сказать... использовать coroutine для перебора элементов некоего stream это себя не любить.

Z>Здесь начинается ваше заблуждение.

Вполне возможно. Я просто сам в поисках оптимального решения поэтому может и смотрю "искоса низко голову наклоня".

CS>>corouitine это отдельный stack. Имплементация оных (corroutines) и в Lua и в Python (generators/yield) выполнена как т.н. называемые "green" thread (a.k.a. cooperative threads, a.k.a. fibers).

CS>>В принципе green thread значительно легче чем OS thread но тем не менее это не самая простая операция.
Z>Еrlang, Lua, Stackless Python, Limbo и.т.д используют VM threads — они очень дешевые ~600-1000 байт на поток, а скорость переключения контекста соизмерима со скоростью вызова функции. Хорошая реализация продолжений (как в Chez) будет не хуже.

Память и количество опреаций на переключение это не единственные ограничения.
Есть еще косвенная доп. нагрузка на GC например.

Z>Т.е. для луа цена вопроса: создание потока — ~300 ns, переключение ~100ns + 1K на стек (ns — это 10e-9 sec). Stackless по моим замерам аналогичен по скорости. Limbo в пару раз быстрее, но он статически типизирован.


Времена в абсолютном значении мало что говорят. Нужны относительные цифири.

Переключение кстати может быть вообще нулевым — вернее равным вызову функции в C.
coroutine (или generator в терминах Python) должна получить stack некоего размера в начале исполнения — 1k это хорошо, но
может потребоваться dynamic resize оного в runtime. Тоже что-то стоит.

Возвращаясь к исходной задаче идеальным наверное является рефакторинг самого метода retrlines
или использование оной как есть т.е. без ненужной for-in beautification.

Z>По поводу структурирования программ посредством микропотоков и передачи сообщений — есть интересная лекция того самого Роба Пайка. Сейчас он работает в Google — разрабатывает для них секретный язык Sawzall. Речь там идет о предтече Limbo, языке Newsqueak.


Z>Video: Advanced Topics in Programming Languages: Concurrency/message passing Newsqueak by Pob Pike


Это действительно интересно. Странно, как-то раньше это прошло мимо меня. Спасибо.
Но кстати как я понимаю эффективной имплементации этого дела так и нет.
Интерпретация UI модели конечно интересная, но в реалии требуется concurrent multitasking что в общем-то
так на так выходит. Ну и в принципе messaging используемый в GUI это и есть те самые channels.
Отказ от примитивов синхронизации в пользу messages — в этом действительно что-то есть как представляется.
Re[13]: Python: s/callback/generator/
От: z00n  
Дата: 19.07.09 09:45
Оценка: 8 (1)
Здравствуйте, c-smile, Вы писали:

CS>Память и количество опреаций на переключение это не единственные ограничения.

CS>Есть еще косвенная доп. нагрузка на GC например.

Z>>Т.е. для луа цена вопроса: создание потока — ~300 ns, переключение ~100ns + 1K на стек (ns — это 10e-9 sec). Stackless по моим замерам аналогичен по скорости. Limbo в пару раз быстрее, но он статически типизирован.


CS>Времена в абсолютном значении мало что говорят. Нужны относительные цифири.


CS>Переключение кстати может быть вообще нулевым — вернее равным вызову функции в C.

CS>coroutine (или generator в терминах Python) должна получить stack некоего размера в начале исполнения — 1k это хорошо, но
CS>может потребоваться dynamic resize оного в runtime. Тоже что-то стоит.

Можно потестировать что-то конктретное.


Z>>По поводу структурирования программ посредством микропотоков и передачи сообщений — есть интересная лекция того самого Роба Пайка.

CS>Это действительно интересно. Странно, как-то раньше это прошло мимо меня. Спасибо.
CS>Но кстати как я понимаю эффективной имплементации этого дела так и нет.

Это встроенные системные фичи обеих post-UNIX операционных систем от Bell Labs — Plan 9 и Inferno. В Plan 9 это библиотека libthreads (ее можно покрутить под линуксом в составе plan9port). На ней, в частности написан оконный менеджер.
Inferno — это OS постоенная поверх виртуальной машины Limbo — работает на голом железе или поверх эмулятора на полудюжине архитектур. Я ее в режиме эмуляции гонял под XP — у нее jit и работает очень шустро.
исходники: http://code.google.com/p/inferno-os/
урезанная Inferno c интерфейсом из Acme: http://code.google.com/p/acme-sac/
бинарники: http://www.vitanuova.com/inferno/net_download4T.html
русские фанаты http://habrahabr.ru/blogs/os_inferno/

CS>Интерпретация UI модели конечно интересная, но в реалии требуется concurrent multitasking что в общем-то так на так выходит.

Ну, в вышепреведенном списке языков потоки кооперативные только у Lua, у Stackless можно и так и этак, у Limbo и Erlang — concurrent. На скорость это практически не влияет.
Re[5]: Python: s/callback/generator/
От: achmed Удмуртия https://www.linkedin.com/in/nail-achmedzhanov-9907188/
Дата: 28.07.09 20:53
Оценка:
Здравствуйте, palm mute, Вы писали:

PM>Здравствуйте, SergH, Вы писали:


SH>>Это всё-таки не вполне полноценные корутины, насколько я понимаю. Питоновская корутина должна возвращать итератор, т.е. объект с предопределённым интерфейсом, у него потом можно вызывать функцию next, а в конце он выбросит исключение. Для возвращаемого значения тут места нет.

PM>Неполноценность питоновских генераторов в другом — ограниченность контекста одной процедурой, тем хорошо раскрыта в Lua wiki.

Интересная ссылка. Всегда обделял Lua вниманием, видимо зря .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.