📜 ⬆️ ⬇️

Landscaping Twisted

As usual, on holidays, in my spare time, from tiling and tacking other skirting boards, I was seized by another idea from the “try” cycle. On Habré slipped article about Pyrant . The first iteration I took and redid the main part of the protocol on Twisted - github.com/Deepwalker/tx-tokyo . And everything was fine, the offensive went on all fronts, but then I went to the pythonous part of the pyrant, and realized that it was impossible to make a yield a [megakey] = 'mega data string'. It was very sad, because in the article I was hooked precisely by the easy handling of the data in the pythonous form. What to do, Pooh, I asked myself? And remembered the greenlet-ah .



After tormenting some time, I rewrote defer.inlineCallbacks to use greenlet-s and was able to write such code:
 from twisted.internet import defer, protocol, reactor from tx_green import inlineCallbacks from greentokyo import Tyrant @inlineCallbacks def test_proto(): t = Tyrant() print t.get_stats() t['kuku'] = 'Green Tyrant!' print t['kuku'] reactor.stop() if __name__=='__main__': test_proto() reactor.run() 

')
Convenience is that greenlets have an important difference from generators - they are not limited to one function. That is, when t ['kuku'] is called, t .__ getitem__ is actually called, inside which we make a switch () call to return control of the main loop for as long as we are waiting for data from the server. If we tried to do inside t .__ getitem__ yield, then we would simply make a generator out of it without getting any benefit.

As you can see, it is enough to wrap one function, and everything inside it will start working in non-blocking mode. And if some modules will use the already modified versions of the underlying modules, their syntax will not change. That is all. Example - I will add my pyrant fork to twisted using greenlet, and I can use models without changes.

The disadvantage is that you need to remember all this stuffing - it will be bad if you wait for the data, and instead you just drop Deferred. And it will be even worse if you forget to return control to the main thread — stop the entire application. And in this version, “not twist your brain” does not shine, because you have to remember and use the features of Twisted.

It should be noted that there is nothing in the above code that clearly indicates a return of control - calls to greenlet.switch () are hidden in the implementation of the pythonous Tyrant. That is, it is sharpened by this implementation. If this were not the case, then we would have to explicitly call the wait function from tx_green. It is this moment that bothers me - you can create almost junga, and calls to the database via ORM will also work secretly causing wait, but if you forget, you can potentially generate a subtle error, or a newcomer, as usual without really reading the documentation, will start requesting Any server page through urllib and will long wonder why the server slows down.

The implementation is located in my sandbox .

Here is a small post. As always, I expect a pleasant discussion, and I hope that there will be good suggestions on the code, as was the case in our last meeting, with me in the postwriter role. Thanks for attention.

Source: https://habr.com/ru/post/80339/


All Articles