Tornado: read/write mit locks sichern
Verfasst: Dienstag 29. Mai 2018, 13:43
Ich habe einen Tornado-Webservice, der eine Vielzahl von Requests pro Sekunde entgegennimmt. Der MainHandler nimmt dabei die Anfragen entgegen und übergibt sie an die Klasse `Store`, welche die Daten aus dem Request lokal auf Platte schreibt. Der Filename trägt dabei die ID, die dem Request übergeben wird. So weit, so gut. Was ich noch nicht ganz verstanden habe bzw. sicherstellen möchte ist, dass die Methode Store.write() nicht blockiert, bzw. die worker asynchron schreiben können. Das scheint mit dem ThreadPoolExecutor soweit zu laufen, jedoch verstehe ich nicht, was genau passiert, wenn z.B. 10 Anfragen gleichzeitig auf ein und das selbe File zugreifen wollen.
Die Applikation ist dabei nie auf die Nase gefallen, ich habe testweise 10 Files mit gleicher File-ID mit á 300 MB gleichzeitig an den Webservice geschickt, alle Files werden dabei ohne Probleme dem File angehängt. Daraus ergibt sich für mich die Frage, was passiert hier? Nach meinem Verständnis müssten doch alle Worker gleichzeitig versuchen, in das File zu schreiben, was aber eigentlich einen Fehler schmeißen sollte, da das File bereits geöffnet wird? Oder stimmt Tornado hier bereits den Zugriff ab, oder aber schreiben alle Worker einfach wirr in das File ?
Zugegeben, Tornado macht regen Gebrauch von Asyncio unter der Haube, wovon ich wenig Praxiserfahrung habe.
Der Code (um o.g. Problem mit dem parallelen Filezugriff zu umgehen habe ich ein lock implementiert. Kannte das bisher nur von threading.Lock() um Zugriffe atomar zu machen):
Die Applikation ist dabei nie auf die Nase gefallen, ich habe testweise 10 Files mit gleicher File-ID mit á 300 MB gleichzeitig an den Webservice geschickt, alle Files werden dabei ohne Probleme dem File angehängt. Daraus ergibt sich für mich die Frage, was passiert hier? Nach meinem Verständnis müssten doch alle Worker gleichzeitig versuchen, in das File zu schreiben, was aber eigentlich einen Fehler schmeißen sollte, da das File bereits geöffnet wird? Oder stimmt Tornado hier bereits den Zugriff ab, oder aber schreiben alle Worker einfach wirr in das File ?
Zugegeben, Tornado macht regen Gebrauch von Asyncio unter der Haube, wovon ich wenig Praxiserfahrung habe.
Der Code (um o.g. Problem mit dem parallelen Filezugriff zu umgehen habe ich ein lock implementiert. Kannte das bisher nur von threading.Lock() um Zugriffe atomar zu machen):
Code: Alles auswählen
from concurrent import futures
from tornado import web, ioloop, gen, concurrent, locks
class Store:
def __init__(self):
self.executor = futures.ThreadPoolExecutor(max_workers=10)
@concurrent.run_on_executor(executor='executor')
def write(self, id, content):
with open(id, 'ab') as fd:
fd.write(content)
class MainHandler(web.RequestHandler):
def initialize(self):
self.store = Store()
self.lock = locks.Lock()
@gen.coroutine
def put(self, id):
with (yield self.lock.acquire()):
yield self.store.write(id, self.request.body)
def start():
return web.Application([
(r"/(.*)", MainHandler),
])
if __name__ == '__main__':
app = start()
app.listen(8888, max_buffer_size=(300*1024*1024))
ioloop.IOLoop.instance().start()