Próbuję zrozumieć, jak korzystać z nowej funkcjonalności asyncio w Pythonie 3.4 i zmagam się z tym, jak korzystać z event_loop.add_reader () <). Z Ograniczone dyskusje, które znalazłem, wygląda na to, że czytanie standardowego Oddzielny proces w przeciwieństwie do zawartości otwartego pliku. Czy to prawda? Jeśli tak, wydaje się, że nie ma asyncio specyficzny sposób, aby zintegrować standardowy plik IO, czy to prawda?

Gram z poniższym kodem. Wyjście poniższych daje wyjątek PermissionError: [Errno 1] Operation not permitted z linii 399 z /Python3.4/selektors.py self._epoll.register(key.fd, epoll_events) jest wywołany przez linię add_reader() poniżej

import asyncio
import urllib.parse
import sys
import pdb
import os

def fileCallback(*args):
    pdb.set_trace()

path = sys.argv[1]
loop = asyncio.get_event_loop()
#fd = os.open(path, os.O_RDONLY)
fd = open(path, 'r')
#data = fd.read()
#print(data)
#fd.close()
pdb.set_trace()
task = loop.add_reader(fd, fileCallback, fd)
loop.run_until_complete(task)
loop.close()

EDYTUJ

Dla tych, którzy szukają przykładu sposobu korzystania z asyncio do czytania więcej niż jednego pliku na raz, jakbym był ciekawy, oto przykład tego, jak można go osiągnąć. Sekret jest w linii yield from asyncio.sleep(0). Zasadniczo zatrzymuje się bieżącą funkcję, umieszczając ją z powrotem w kolejce pętli zdarzeń, do wywołania po wykonaniu wszystkich innych gotowych funkcji. Funkcje są zdecydowane być gotowe na podstawie tego, jak zostały zaplanowane.

import asyncio

@asyncio.coroutine
def read_section(file, length):
    yield from asyncio.sleep(0)
    return file.read(length)

@asyncio.coroutine
def read_file(path):
    fd = open(path, 'r')
    retVal = []
    cnt = 0
    while True:
        cnt = cnt + 1
        data = yield from read_section(fd, 102400)
        print(path + ': ' + str(cnt) + ' - ' + str(len(data)))
        if len(data) == 0:
            break;
    fd.close()

paths = ["loadme.txt", "loadme also.txt"]
loop = asyncio.get_event_loop()
tasks = []
for path in paths:
    tasks.append(asyncio.async(read_file(path)))
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
7
Josh Russo 17 sierpień 2014, 21:55

2 odpowiedzi

Najlepsza odpowiedź

Funkcje te oczekują deskryptora plików, to znaczy, podstawowe liczby całkowite używa systemu operacyjnego, a nie obiekty plików Pythona. Obiekty plików, które są oparte na deskryptach plików zwracają ten deskryptor na metodzie fileno(), więc na przykład:

>>> sys.stderr.fileno()
2

W UNIX deskrypci plików mogą być dołączone do plików lub wielu innych rzeczy, w tym innych procesów.

Edytuj dla Edycja OP:

Jak mówi Max w komentarzach, nie możesz użyć epoll w lokalnych plikach (i asyncio używa epoll). Tak, to jest dziwne. Możesz jednak użyć go na rurach, na przykład:

import asyncio
import urllib.parse
import sys
import pdb
import os

def fileCallback(*args):
    print("Received: " + sys.stdin.readline())

loop = asyncio.get_event_loop()
task = loop.add_reader(sys.stdin.fileno(), fileCallback)
loop.run_forever()

To będzie echo piszesz na stdin.

8
Jorgen Schäfer 17 sierpień 2014, 18:23

Nie można użyć Dodaj_Reader na lokalnych plikach, ponieważ:

  • Nie można tego zrobić za pomocą Wybierz / Eld / EPOLL
  • Zależy to od systemu operacyjnego
  • Nie może być w pełni asynchroniczny ze względu na ograniczenia systemu operacyjnego (Linux nie obsługuje Metadanych ASync FS Read / zapis)

Ale, technicznie, tak, powinieneś być w stanie wykonać Async Read / Write, (prawie) Wszystkie systemy mają mechanizm DMA do robienia I / O "w tle". I nie, lokalny I / O nie jest naprawdę Naprawdę Szybko tak, że nikt nie chciał, że procesor są rzędu milionów razy szybciej, że dysk I / O.

Szukaj aiofile lub aiofiles, jeśli chcesz spróbować async I / O

0
Michel 26 luty 2019, 00:02