2012-03-21 18 views
7

Próbuję odczytać linię z IO w sposób nieblokujący.Nie blokująca linii rubla czytaj

Niestety bloki readline. Myślę, że mogę rozwiązać ten problem z read_nonblock z dodatkowym buforem, w którym przechowuję wynik częściowy, sprawdzam, czy w buforze jest wiele linii, itd., Ale wydaje się to nieco skomplikowane w przypadku prostego zadania takiego jak to. Czy jest lepszy sposób to zrobić?

Uwaga: Używam demultipleksowanie zdarzeń (select) i jestem bardzo z niego zadowolony, nie chcę tworzyć tematy, użyj EventMachine, etc ...

Odpowiedz

5

myślę, że jest rozwiązanie read_nonblock prawdopodobnie droga. Proste, nie maksymalnie wydajna wersja monkey-patch:

class IO 
    def readline_nonblock 
    rlnb_buffer = "" 
    while ch = self.read_nonblock(1) 
     rlnb_buffer << ch 
     if ch == "\n" then 
     result = rlnb_buffer 
     return result 
     end 
    end  
    end 
end  

To zgłasza wyjątek, jeśli nie jest gotowy Brak danych, podobnie jak read_nonblock, więc trzeba ratować, że po prostu uzyskać nil powrotem itd

+0

tak, to był mój oryginalny pomysł, i to, co w końcu zrobił, ale czytałem jak mogę (nie tylko jeden znak), myślę, że to jest lepsze dla wydajności. Dzięki za końcówkę monke-patch;) –

3

ta implementacja poprawia odpowiedź Mark Reeda przez nie odrzucając odczytu danych, który nie kończy się znakiem nowej linii:

class IO 
    def readline_nonblock 
    buffer = "" 
    buffer << read_nonblock(1) while buffer[-1] != "\n" 

    buffer 
    rescue IO::WaitReadable => blocking 
    raise blocking if buffer.empty? 

    buffer 
    end 
end 
+1

"bez gwarancji" - to trochę przerażające. nie polegaj na nieudokumentowanych "funkcjach". "Testowałem to" - dokładnie? z różnymi metodami wprowadzania? Mogło to zadziałać tylko dlatego, że twoje dane wejściowe były buforowane liniowo ... –

+0

Nie byłem na tyle odważny, aby na nim polegać, dlatego włączyłem drugą część. :-) –

+0

Sprawdziłem, że 'read_nonblock (4096)' nie zwraca pojedynczej linii na ruby ​​1.9.3, 2.0.0 i 2.1.3. Lepiej skorzystaj z tej sugestii. Łatwo sprawdzić za pomocą 'ruby19 -e 'x = IO.popen (" cat/etc/fstab "); spać 0,2; p x.read_nonblock (4096) ". – chutz