twisted

40
Twisted Michal Sedlak [email protected]

Upload: michal-sedlak

Post on 08-May-2015

2.069 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Twisted

Twisted

Michal [email protected]

Page 2: Twisted

2

Based on

Dave Peticolas: Twisted Introductionhttp://krondo.com/?page_id=1327

Orestis Markou: Asynchronous programming with Twisted

http://ep2011.europython.eu/conference/talks/asynchronous-programming-with-twisted

https://github.com/orestis/twisted-tutorial

Twisted documentation

http://twistedmatrix.com/documents

Page 3: Twisted

3

Outline

● What is Twisted?● Why Twisted?

● Async vs. Sync● Blocking vs. Non Blocking

● Parts:● Reactor● Factory● Protocol● Transfer

Page 4: Twisted

4

What is Twisted

Twisted is a networking engine written in Python, supporting numerous protocols.

It contains a web server, numerous chat clients, chat servers, mail servers, and more.

http://twistedmatrix.com/trac/wiki/TwistedProjects

Page 5: Twisted

5

Why use Twisted

● Python... 2 :(● Asynchronous and event-based● Full-featured

● Mail, web, news, chat, DNS, SSH, Telnet, RPC, database access, and more

● Flexible● Open source

http://www.eecho.info/Echo/python/why-use-twisted/

Page 6: Twisted

6

Async? Eventbased?

● Single thread● Synchronous● Asynchronous

● Multi-thread

Page 7: Twisted

7

Synchronous model

● 3 tasks● One after another● Simple flow

Page 8: Twisted

8

Threaded model

● Parallel execution● Complex flow coordination

● IPC, critical section, race condition, synchronisation

Page 9: Twisted

9

Asynchronous model

● Interleaved tasks● Sequence of small steps● More complex than sync

No parallelism!

Q: Same execution time as in sync model?

Page 10: Twisted

10

Typical network server blocksimport sockets = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.bind((HOST, PORT))s.listen(1)while 1:    conn, addr = s.accept()    while 1:        data = conn.recv(1024)        if not data: break        conn.send(data)    conn.close()

Page 11: Twisted

11

Blocking

● Some function calls blocks and sync programs waits

● I/O● CPU much faster then:

● Disk● Network

Page 12: Twisted

12

When and why async?

● Many tasks● Interactive● Independent tasks

● Non-blocking● Responsive● Less interprocess

communication means less waiting for processes

Network services

Page 13: Twisted

13

How?

● Low level I/O - Platform dependent● Socket – setblocking(0)● Async Disk I/O

– Python 3 - http://www.python.org/dev/peps/pep-3116/– Twisted

http://twistedmatrix.com/documents/8.1.0/api/twisted.internet.fdesc.html#setNonBlocking

● Reactor pattern and async libs - Twisted

Page 14: Twisted

14

Twisted basic parts

● Reactor● Endpoint● Factory● Protocol● Transfer● Deferred

Page 15: Twisted

15

Page 16: Twisted

16

Reactor

● Wait for I/O● Handle Event

● Q: What if event handler blocks?

Page 17: Twisted

17

Blocking event handlerstops application

Page 18: Twisted

18

● potentially blocking operations● reading or writing from a non-socket file descriptor

(pipe)● waiting for a subprocess to finish

● Switch from blocking to non-blocking?● Many standard Python functions are blocking only● Example: os.system – always block● Use Twisted API :)

Page 19: Twisted

19

First server

● The reactor isn’t created explicitly, just imported.

● reactor.run(), reactor.stop()

● The reactor loop runs in the same thread it was started in.

● Once the loop starts up, it just keeps going.

● If it doesn’t have anything to do, the reactor loop does not consume CPU.

● Default reactor is twisted.internet.selectreactor

from twisted.internet import reactorreactor.run()

Page 20: Twisted

20

ReactorStatus T

CP

SSL

UDP

Threading Processes Scheduling

Platforms

select() Stable Y Y Y Y Y Y Unix, Win32

poll Stable Y Y Y Y Y Y Unix

WaitForMultipleObjects

Experimental Y Y Y Y Y Y Win32

Input/Output Completion Port

Experimental Y Y N N N Y Win32

CoreFoundation Unmaintained Y Y Y Y Y Y Mac OS X

epoll Stable Y Y Y Y Y Y Linux 2.6

GTK+ Stable Y Y Y Y Y Y Unix, Win32

wx Experimental Y Y Y Y Y Y Unix, Win32

kqueue Experimental Y Y Y Y Y Y FreeBSD

http://twistedmatrix.com/documents/current/core/howto/choosing-reactor.html

Page 21: Twisted

21

from twisted.internet import pollreactorpollreactor.install()

from twisted.internet import reactorreactor.run()

Change reactor

Page 22: Twisted

22

Page 23: Twisted

23

Factory

● persistent configuration common to all connections

● instantiates “protocol”● access persistence: protocol_instance.factory● factory does not listen to connections● same service on multiple ports or network

addresses

Page 24: Twisted

24

Page 25: Twisted

25

Protocol

● Per connection instance● Protocol handling● DataReceived(): Called whenever data is received.● ConnectionLost(): Called when the connection is

shut down.● MakeConnection(): Make a connection to a transport

and a server.● ConnectionMade(): Called when a connection is

made.

Page 26: Twisted

26

Page 27: Twisted

27

Transport

● Represents physical connection● write(): send data over connection● GetPeer()● GetHost()● loseConnection()

Page 28: Twisted

28

Page 29: Twisted

29

Endpoint

● Listener or connector abstraction

cep = clientFromString(reactor "tcp:host=www.example.com:port=80")

cep.connect(factory)

cep = clientFromString(reactor,     "ssl:host=web.example.com:port=443:" 

     "privateKey=foo.pem:certKey=foo.pem")cep.connect(factory)

Page 30: Twisted

30

sep = serverFromString(reactor, "tcp:80:interface=127.0.0.1")

sep.listen(factory)

sep = serverFromString(reactor, "unix:/var/run/finger:mode=660")

sep.listen(factory)

Page 31: Twisted

31

Summary

● Reactor is most important● reactor.run()● Appropriate endpoint.● Protocol factory to create protocol instances● Protocol instances only deal with a single connection● Shared state in factory● Data arrive in chunks● Implementing protocols is hard. Reuse as much code as

possible

Page 32: Twisted

32

What's next?

● Server example● Deferred - promise● Database handling – Async?● Error handling – reverse error flow● Trial

Page 33: Twisted

33

First server

● Proxy at localhost:8000● Input: URL● Output: Fetched data

Page 34: Twisted

34

import timeimport urllib2

from twisted.protocols import basic

class ProxyProtocol(basic.LineReceiver):    def lineReceived(self, url):        if not url.startswith('http://'):            return        start = time.time()        print 'fetching', url        connection = urllib2.urlopen(url)        data = connection.read()        print 'fetched', url,        self.transport.write(data)        self.transport.loseConnection()        print 'in', time.time() ­ start

First server

Page 35: Twisted

35

from twisted.internet import protocolclass ProxyFactory(protocol.ServerFactory):    protocol = ProxyProtocol

from twisted.internet import reactor, endpoints

endpoint = endpoints.TCP4ServerEndpoint(reactor, 8000)factory = ProxyFactory()endpoint.listen(factory)

reactor.run()

Page 36: Twisted

36

Run

Site   Server Client=====  ====== ======A      0.771  3.817B      0.567  2.026C      1.457  2.026D      1.019  3.815­­­­­  ­­­­­­ ­­­­­­Total: 3.813  3.817

Why same download times?

c = urllib2.urlopen(url)

data=c.read()

Page 37: Twisted

37

We need async url data fetcher

● twisted.web.client.getPage● http://launchpad.net/tx

Page 38: Twisted

38

import timefrom twisted.web import clientfrom twisted.protocols import basic

class ProxyProtocol(basic.LineReceiver):

    def lineReceived(self, url):        if not url.startswith('http://'):            return        start = time.time()        print 'fetching', url        deferredData = client.getPage(url)

        def urlFetched(data):            self.transport.write(data)            self.transport.loseConnection()            print 'fetched', url,            print 'in', time.time() ­ start

        deferredData.addCallback(urlFetched)

Page 39: Twisted

39

from twisted.internet import protocolclass ProxyFactory(protocol.ServerFactory):    protocol = ProxyProtocol

from twisted.internet import reactor, endpoints

endpoint = endpoints.TCP4ServerEndpoint(reactor, 8000)factory = ProxyFactory()endpoint.listen(factory)

reactor.run()

Page 40: Twisted

40

Site  Server Client===== ====== ======A      0.850  0.853B      0.486  0.488C      1.582  1.584D      0.999  1.000­­­­­ ­­­­­­ ­­­­­­Total: 3.918  1.585

Better :)