SlideShare a Scribd company logo
1 of 93
Download to read offline
WRITING REDIS IN PYTHON
WITH ASYNCIO
James Saryerwinnie / @jsaryer
GOALS
‣ How to structure a “larger” network server application
‣ Request/Response structure
‣ Publish/Subscribe
‣ Blocking queues
ABOUT ME
‣ AWS CLI
‣ Boto3/botocore/boto
‣ JMESPath
‣ AWS Shell
‣ Chalice
s Really Work (version 1.0) Create your own cartoon at www.projectc
customer
ned it
How the project leader
understood it
How the analyst designed
it
How the programmer
wrote it
How the business
consultant described it
http://www.projectcartoon.com/cartoon/3
How the authors envisioned it
How Projects Really Work (version 1.0)
How the customer
explained it
How the project leader
understood it
How the analyst designed
it
How
version 1.0) Create your own cartoon at www.projectcartoon.com
w the project leader
understood it
How the analyst designed
it
How the programmer
wrote it
How the business
consultant described it
What might happen here
REDIS
‣ Data structure server
‣ Set and get key value pairs
‣ Values can be more than string
RedisClient
GET foo
bar
RedisClient
SET foo bar
OK
RedisClient
LPOP foo
a
RedisClient
RPUSH foo a
RPUSH foo b
RPUSH foo c LRANGE foo 0 2
b, c
REQUEST / RESPONSE
RedisClient
GET foo
bar
What we want
server.py
import asyncio
loop = asyncio.get_event_loop()
coro = loop.create_server(RedisServerProtocol, '127.0.0.1', 6379)
server = loop.run_until_complete(coro)
try:
loop.run_forever()
except KeyboardInterrupt:
pass
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
server.py
import asyncio
loop = asyncio.get_event_loop()
coro = loop.create_server(RedisServerProtocol, '127.0.0.1', 6379)
server = loop.run_until_complete(coro)
try:
loop.run_forever()
except KeyboardInterrupt:
pass
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
server.py
import asyncio
loop = asyncio.get_event_loop()
coro = loop.create_server(RedisServerProtocol, '127.0.0.1', 6379)
server = loop.run_until_complete(coro)
try:
loop.run_forever()
except KeyboardInterrupt:
pass
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
server.py
import asyncio
loop = asyncio.get_event_loop()
coro = loop.create_server(RedisServerProtocol, '127.0.0.1', 6379)
server = loop.run_until_complete(coro)
try:
loop.run_forever()
except KeyboardInterrupt:
pass
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
server.py
import asyncio
loop = asyncio.get_event_loop()
coro = loop.create_server(RedisServerProtocol, '127.0.0.1', 6379)
server = loop.run_until_complete(coro)
try:
loop.run_forever()
except KeyboardInterrupt:
pass
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
protocol.py
class RedisServerProtocol(asyncio.Protocol):
def connection_made(self, transport):
self.transport = transport
def data_received(self, data):
pass
How do these work?
Let’s look under the hood
server.py
import asyncio
loop = asyncio.get_event_loop()
coro = loop.create_server(RedisServerProtocol, '127.0.0.1', 6379)
server = loop.run_until_complete(coro)
try:
loop.run_forever()
except KeyboardInterrupt:
pass
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
server.py
import asyncio
loop = asyncio.get_event_loop()
coro = loop.create_server(RedisServerProtocol, '127.0.0.1', 6379)
server = loop.run_until_complete(coro)
try:
loop.run_forever()
except KeyboardInterrupt:
pass
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
asyncio/selector_events.py
def _accept_connection2(
self, protocol_factory, conn, extra, server=None):
protocol = None
transport = None
try:
protocol = protocol_factory() # RedisServerProtocol
waiter = futures.Future(loop=self)
transport = _SelectorSocketTransport(self, sock, protocol,
waiter, extra, server)
# ...
except Exception as exc:
# ...
pass
asyncio/selector_events.py
def _accept_connection2(
self, protocol_factory, conn, extra, server=None):
protocol = None
transport = None
try:
protocol = protocol_factory() # RedisServerProtocol
waiter = futures.Future(loop=self)
transport = _SelectorSocketTransport(self, sock, protocol,
waiter, extra, server)
# ...
except Exception as exc:
# ...
pass
ProtocolTransport
ProtocolTransport
ProtocolTransport
client_connected
client_connected
client_connected
asyncio/selector_events.py
class _SelectorSocketTransport(_SelectorTransport):
def __init__(self, loop, sock, protocol, waiter=None,
extra=None, server=None):
super().__init__(loop, sock, protocol, extra, server)
self._eof = False
self._paused = False
self._loop.call_soon(self._protocol.connection_made, self)
# only start reading when connection_made() has been called
self._loop.call_soon(self._loop.add_reader,
self._sock_fd, self._read_ready)
asyncio/selector_events.py
class _SelectorSocketTransport(_SelectorTransport):
def __init__(self, loop, sock, protocol, waiter=None,
extra=None, server=None):
super().__init__(loop, sock, protocol, extra, server)
self._eof = False
self._paused = False
self._loop.call_soon(self._protocol.connection_made, self)
# only start reading when connection_made() has been called
self._loop.call_soon(self._loop.add_reader,
self._sock_fd, self._read_ready)
asyncio/selector_events.py
class _SelectorSocketTransport(_SelectorTransport):
def __init__(self, loop, sock, protocol, waiter=None,
extra=None, server=None):
super().__init__(loop, sock, protocol, extra, server)
self._eof = False
self._paused = False
self._loop.call_soon(self._protocol.connection_made, self)
# only start reading when connection_made() has been called
self._loop.call_soon(self._loop.add_reader,
self._sock_fd, self._read_ready)
asyncio/selector_events.py
def _read_ready(self):
try:
data = self._sock.recv(self.max_size)
except (BlockingIOError, InterruptedError):
pass
except Exception as exc:
self._fatal_error(exc, 'Fatal read error')
else:
if data:
self._protocol.data_received(data)
else:
pass
asyncio/selector_events.py
def _read_ready(self):
try:
data = self._sock.recv(self.max_size)
except (BlockingIOError, InterruptedError):
pass
except Exception as exc:
self._fatal_error(exc, 'Fatal read error')
else:
if data:
self._protocol.data_received(data)
else:
pass
protocol.py
class RedisServerProtocol(asyncio.Protocol):
def connection_made(self, transport):
self.transport = transport
def data_received(self, data):
pass
Callbacks
ProtocolTransport
ProtocolTransport
ProtocolTransport
ProtocolTransport
Event Loop
data_received()
data_received()
data_received()
data_received()
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def __init__(self, db):
self._db = db
def connection_made(self, transport):
self.transport = transport
def data_received(self, data):
parsed = parser.parse_wire_protocol(data)
# [b"SET", b"foo", b"bar"]
command = parsed[0].lower()
if command == b'get':
response = self._db.get(parsed[1])
elif command == b'set':
response = self._db.set(parsed[1], parsed[2])
wire_response = serializer.serialize_to_wire(response)
self.transport.write(wire_response)
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def __init__(self, db):
self._db = db
def connection_made(self, transport):
self.transport = transport
def data_received(self, data):
parsed = parser.parse_wire_protocol(data)
# [b"SET", b"foo", b"bar"]
command = parsed[0].lower()
if command == b'get':
response = self._db.get(parsed[1])
elif command == b'set':
response = self._db.set(parsed[1], parsed[2])
wire_response = serializer.serialize_to_wire(response)
self.transport.write(wire_response)
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def __init__(self, db):
self._db = db
def connection_made(self, transport):
self.transport = transport
def data_received(self, data):
parsed = parser.parse_wire_protocol(data)
# [b"SET", b"foo", b"bar"]
command = parsed[0].lower()
if command == b'get':
response = self._db.get(parsed[1])
elif command == b'set':
response = self._db.set(parsed[1], parsed[2])
wire_response = serializer.serialize_to_wire(response)
self.transport.write(wire_response)
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def __init__(self, db):
self._db = db
def connection_made(self, transport):
self.transport = transport
def data_received(self, data):
parsed = parser.parse_wire_protocol(data)
# [b"SET", b"foo", b"bar"]
command = parsed[0].lower()
if command == b'get':
response = self._db.get(parsed[1])
elif command == b'set':
response = self._db.set(parsed[1], parsed[2])
wire_response = serializer.serialize_to_wire(response)
self.transport.write(wire_response)
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def __init__(self, db):
self._db = db
def connection_made(self, transport):
self.transport = transport
def data_received(self, data):
parsed = parser.parse_wire_protocol(data)
# [b"SET", b"foo", b"bar"]
command = parsed[0].lower()
if command == b'get':
response = self._db.get(parsed[1])
elif command == b'set':
response = self._db.set(parsed[1], parsed[2])
wire_response = serializer.serialize_to_wire(response)
self.transport.write(wire_response)
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def __init__(self, db):
self._db = db
def connection_made(self, transport):
self.transport = transport
def data_received(self, data):
parsed = parser.parse_wire_protocol(data)
# [b"SET", b"foo", b"bar"]
command = parsed[0].lower()
if command == b'get':
response = self._db.get(parsed[1])
elif command == b'set':
response = self._db.set(parsed[1], parsed[2])
wire_response = serializer.serialize_to_wire(response)
self.transport.write(wire_response)
b'*3rn$3rnSETrn$3rnfoorn$3rnbarrn'
b'+OKrn'
rserver/db.py
_DB = {}
class DB:
def __init__(self, db=None):
if db is None:
db = _DB
self._db = db
def get(self, item):
return self._db.get(item)
def set(self, item, value):
self._db[item] = value
return True
‣ DB is in its own separate module
‣ It doesn’t know anything about asyncio
rserver/db.py
class DB:
def rpush(self, item, values):
current_list = self._db.setdefault(item, [])
current_list.extend(values)
return len(current_list)
def lrange(self, key, start, stop):
if stop == -1:
end = None
else:
stop += 1
return self._db.get(key, [])[start:stop]
def lpop(self, key):
value = self._db.get(key, [])
if value:
return value.pop(0)
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def data_received(self, data):
parsed = parser.parse_wire_protocol(data)
# [b"SET", b"foo", b"bar"]
command = parsed[0].lower()
if command == b'get':
response = self._db.get(parsed[1])
elif command == b'set':
response = self._db.set(parsed[1], parsed[2])
elif command == b'rpush':
response = self._db.rpush(parsed[1], parsed[2:])
elif command == b'lrange':
response = self._db.lrange(parsed[1], int(parsed[2]),
int(parsed[3]))
wire_response = serializer.serialize_to_wire(response)
self.transport.write(wire_response)
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def data_received(self, data):
parsed = parser.parse_wire_protocol(data)
# [b"SET", b"foo", b"bar"]
command = parsed[0].lower()
if command == b'get':
response = self._db.get(parsed[1])
elif command == b'set':
response = self._db.set(parsed[1], parsed[2])
elif command == b'rpush':
response = self._db.rpush(parsed[1], parsed[2:])
elif command == b'lrange':
response = self._db.lrange(parsed[1], int(parsed[2]),
int(parsed[3]))
wire_response = serializer.serialize_to_wire(response)
self.transport.write(wire_response)
RedisClient
GET foo
bar
What we have
PUBLISH / SUBSCRIBE
Redis
Client SUBSCRIBE foo
Client SUBSCRIBE foo
Client
PUBLISH foo hello
hello
What we want - PUBLISH/SUBSCRIBE
hello
ProtocolTransport
ProtocolTransport
ProtocolTransport
client_connected
client_connected
client_connected
ProtocolProtocolFactory
Protocol
Protocol
def _accept_connection2(…):
try:
protocol = protocol_factory()
waiter = futures.Future(loop=self)
transport = _SelectorSocketTransport(
self, sock, protocol,
waiter, extra, server)
# ...
except Exception as exc:
# ...
pass
rserver/server.py
class PubSub:
def __init__(self):
self._channels = {}
def subscribe(self, channel, transport):
self._channels.setdefault(channel, []).append(transport)
return ['subscribe', channel, 1]
def publish(self, channel, message):
transports = self._channels.get(channel, [])
message = serializer.serialize_to_wire(
['message', channel, message])
for transport in transports:
transport.write(message)
return len(transports)
rserver/server.py
class PubSub:
def __init__(self):
self._channels = {}
def subscribe(self, channel, transport):
self._channels.setdefault(channel, []).append(transport)
return ['subscribe', channel, 1]
def publish(self, channel, message):
transports = self._channels.get(channel, [])
message = serializer.serialize_to_wire(
['message', channel, message])
for transport in transports:
transport.write(message)
return len(transports)
rserver/server.py
class PubSub:
def __init__(self):
self._channels = {}
def subscribe(self, channel, transport):
self._channels.setdefault(channel, []).append(transport)
return ['subscribe', channel, 1]
def publish(self, channel, message):
transports = self._channels.get(channel, [])
message = serializer.serialize_to_wire(
['message', channel, message])
for transport in transports:
transport.write(message)
return len(transports)
rserver/server.py
class RedisServerProtocol(asyncio.Protocol):
def data_received(self, data):
parsed = parser.parse_wire_protocol(data)
# [COMMAND, arg1, arg2]
command = parsed[0].lower()
if command == b'subscribe':
response = self._pubsub.subscribe(
parsed[1], self.transport)
elif command == b'publish':
response = self._pubsub.publish(parsed[1], parsed[2])
wire_response = serializer.serialize_to_wire(response)
self.transport.write(wire_response)
rserver/server.py
class RedisServerProtocol(asyncio.Protocol):
def data_received(self, data):
parsed = parser.parse_wire_protocol(data)
# [COMMAND, arg1, arg2]
command = parsed[0].lower()
if command == b'subscribe':
response = self._pubsub.subscribe(
parsed[1], self.transport)
elif command == b'publish':
response = self._pubsub.publish(parsed[1], parsed[2])
wire_response = serializer.serialize_to_wire(response)
self.transport.write(wire_response)
server.py
import asyncio
loop = asyncio.get_event_loop()
coro = loop.create_server(RedisServerProtocol, '127.0.0.1', 6379)
server = loop.run_until_complete(coro)
try:
loop.run_forever()
except KeyboardInterrupt:
pass
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
server.py
import asyncio
loop = asyncio.get_event_loop()
factory = ProtocolFactory(
RedisServerProtocol, db.DB(), PubSub(),
)
coro = loop.create_server(factory, '127.0.0.1', 6379)
server = loop.run_until_complete(coro)
try:
loop.run_forever()
except KeyboardInterrupt:
pass
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
rserver/server.py
class ProtocolFactory:
def __init__(self, protocol_cls, *args, **kwargs):
self._protocol_cls = protocol_cls
self._args = args
self._kwargs = kwargs
def __call__(self):
# No arg callable is used to instantiate
# protocols in asyncio.
return self._protocol_cls(*self._args, **self._kwargs)
ProtocolFactory PubSub
ProtocolProtocolProtocol
DB
Transport Transport Transport
BLOCKING LIST POP
Redis
Client BLPOP foo 0
Client BLPOP foo 0
Client
RPUSH foo bar
bar
What we want - BLPOP
How do we do this?
ProtocolFactory KeyBlocker
ProtocolProtocolProtocol
rserver/db.py
from rserver import types
class DB:
def blpop(self, key):
value = self._db.get(key, [])
if value:
element = value.pop(0)
return element
return types.MUST_WAIT
rserver/db.py
from rserver import types
class DB:
def blpop(self, key):
value = self._db.get(key, [])
if value:
element = value.pop(0)
return element
return types.MUST_WAIT
rserver/db.py
from rserver import types
class DB:
def blpop(self, key):
value = self._db.get(key, [])
if value:
element = value.pop(0)
return element
return types.MUST_WAIT
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def __init__(self, db, keyblocker, loop):
self._db = db
self._keyblocker = keyblocker
self._loop = loop
def data_received(self, data):
# …
if command == b'blpop':
response = self._db.blpop(
parsed[1], timeout=int(parsed[2]))
if response is types.MUST_WAIT:
q = self._keyblocker.wait_for_key(parsed[1],
self.transport)
self._loop.create_task(q)
return
class RedisServerProtocol(asyncio.Protocol):
def __init__(self, db, keyblocker, loop):
self._db = db
self._keyblocker = keyblocker
self._loop = loop
def data_received(self, data):
# …
if command == b'blpop':
response = self._db.blpop(
parsed[1], timeout=int(parsed[2]))
if response is types.MUST_WAIT:
q = self._keyblocker.wait_for_key(parsed[1],
self.transport)
self._loop.create_task(q)
return
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def __init__(self, db, keyblocker, loop):
self._db = db
self._keyblocker = keyblocker
self._loop = loop
def data_received(self, data):
# …
if command == b'blpop':
response = self._db.blpop(
parsed[1], timeout=int(parsed[2]))
if response is types.MUST_WAIT:
q = self._keyblocker.wait_for_key(parsed[1],
self.transport)
self._loop.create_task(q)
return
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def __init__(self, db, keyblocker, loop):
self._db = db
self._keyblocker = keyblocker
self._loop = loop
def data_received(self, data):
# …
if command == b'blpop':
response = self._db.blpop(
parsed[1], timeout=int(parsed[2]))
if response is types.MUST_WAIT:
q = self._keyblocker.wait_for_key(parsed[1],
self.transport)
self._loop.create_task(q)
return
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def __init__(self, db, keyblocker, loop):
self._db = db
self._keyblocker = keyblocker
self._loop = loop
def data_received(self, data):
# …
if command == b'blpop':
response = self._db.blpop(
parsed[1], timeout=int(parsed[2]))
if response is types.MUST_WAIT:
q = self._keyblocker.wait_for_key(parsed[1],
self.transport)
self._loop.create_task(q)
return
rserver/protocol.py
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def data_received(self, data):
# …
command = parsed[0].lower()
if command == b'rpush':
response = self._db.rpush(parsed[1], parsed[2:])
self._loop.create_task(
self._keyblocker.data_for_key(parsed[1], parsed[2]))
rserver/protocol.py
class RedisServerProtocol(asyncio.Protocol):
def data_received(self, data):
# …
command = parsed[0].lower()
if command == b'rpush':
response = self._db.rpush(parsed[1], parsed[2:])
self._loop.create_task(
self._keyblocker.data_for_key(parsed[1], parsed[2]))
rserver/server.py
class KeyBlocker:
def __init__(self):
self._blocked_keys = {}
async def wait_for_key(self, key, transport):
if key not in self._blocked_keys:
self._blocked_keys[key] = asyncio.Queue()
q = self._blocked_keys[key]
value = await q.get()
transport.write(
serializer.serialize_to_wire(value)
)
async def data_for_key(self, key, value):
_LOG.debug("Running data_for_key: %s, value: %s", key, value)
if key in self._blocked_keys:
q = self._blocked_keys[key]
await q.put(value)
_LOG.debug("item put in q via q.put()")
class KeyBlocker:
def __init__(self):
self._blocked_keys = {}
async def wait_for_key(self, key, transport):
if key not in self._blocked_keys:
self._blocked_keys[key] = asyncio.Queue()
q = self._blocked_keys[key]
value = await q.get()
transport.write(
serializer.serialize_to_wire(value)
)
async def data_for_key(self, key, value):
_LOG.debug("Running data_for_key: %s, value: %s", key, value)
if key in self._blocked_keys:
q = self._blocked_keys[key]
await q.put(value)
_LOG.debug("item put in q via q.put()")
rserver/server.py
class KeyBlocker:
def __init__(self):
self._blocked_keys = {}
async def wait_for_key(self, key, transport):
if key not in self._blocked_keys:
self._blocked_keys[key] = asyncio.Queue()
q = self._blocked_keys[key]
value = await q.get()
transport.write(
serializer.serialize_to_wire(value)
)
async def data_for_key(self, key, value):
_LOG.debug("Running data_for_key: %s, value: %s", key, value)
if key in self._blocked_keys:
q = self._blocked_keys[key]
await q.put(value)
_LOG.debug("item put in q via q.put()")
rserver/server.py
class KeyBlocker:
def __init__(self):
self._blocked_keys = {}
async def wait_for_key(self, key, transport):
if key not in self._blocked_keys:
self._blocked_keys[key] = asyncio.Queue()
q = self._blocked_keys[key]
value = await q.get()
transport.write(
serializer.serialize_to_wire(value)
)
async def data_for_key(self, key, value):
_LOG.debug("Running data_for_key: %s, value: %s", key, value)
if key in self._blocked_keys:
q = self._blocked_keys[key]
await q.put(value)
_LOG.debug("item put in q via q.put()")
rserver/server.py
rserver/server.py
class KeyBlocker:
def __init__(self):
self._blocked_keys = {}
async def wait_for_key(self, key, transport):
if key not in self._blocked_keys:
self._blocked_keys[key] = asyncio.Queue()
q = self._blocked_keys[key]
value = await q.get()
transport.write(
serializer.serialize_to_wire(value)
)
async def data_for_key(self, key, value):
_LOG.debug("Running data_for_key: %s, value: %s", key, value)
if key in self._blocked_keys:
q = self._blocked_keys[key]
await q.put(value)
_LOG.debug("item put in q via q.put()")
Event Loop
wait_for_key
Event Loop
q.get()
wait_for_key
Event Loop
q.get()
wait_for_key
Event Loop
yield
q.get()
wait_for_key
Event Loop
yield
q.get()
wait_for_key
Event Loop
yield
future
q.get()
wait_for_key
Event Loop
yield
future
q.get()
wait_for_key
Event Loop
yield
future
data_for_key
q.get()
wait_for_key
Event Loop
yield
future
q.put()
data_for_key
q.get()
wait_for_key
Event Loop
yield
future
q.put()
data_for_key
value
q.get()
wait_for_key
Event Loop
yield
future
q.put()
data_for_key
value
q.get()
wait_for_key
Event Loop
yield
q.put()
data_for_key
value
q.get()
wait_for_key
Event Loop
yield
q.put()
data_for_key
value
q.get()
wait_for_key
Event Loop
value
rserver/server.py
class KeyBlocker:
def __init__(self):
self._blocked_keys = {}
async def wait_for_key(self, key, transport):
if key not in self._blocked_keys:
self._blocked_keys[key] = asyncio.Queue()
q = self._blocked_keys[key]
value = await q.get()
transport.write(
serializer.serialize_to_wire(value)
)
ADDITIONAL CONSIDERATIONS
‣ “Real” parsing is more complicated
‣ Pub/sub handles clients disconnecting
‣ Pub/sub globs
‣ Blocking queues can wait on multiple keys
PERFORMANCE
‣ redis-benchmark -n 100000 -t set,get -c 50
‣ redis-server: 82563 requests per second (gets/sets)
‣ pyredis-server: 24192 requests per second
‣ pyredis-server (uvloop): 38285 requests per second
WHAT WE LEARNED
‣ Transports and Protocols
‣ Simple request response
‣ Publish / Subscribe
‣ Blocking queue like behavior
THANKS!
‣ For more info: @jsaryer

More Related Content

What's hot

node.js practical guide to serverside javascript
node.js practical guide to serverside javascriptnode.js practical guide to serverside javascript
node.js practical guide to serverside javascript
Eldar Djafarov
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf Conference
 

What's hot (20)

node.js practical guide to serverside javascript
node.js practical guide to serverside javascriptnode.js practical guide to serverside javascript
node.js practical guide to serverside javascript
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Node.js API 서버 성능 개선기
Node.js API 서버 성능 개선기Node.js API 서버 성능 개선기
Node.js API 서버 성능 개선기
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
Practical Testing of Ruby Core
Practical Testing of Ruby CorePractical Testing of Ruby Core
Practical Testing of Ruby Core
 
ES6: The Awesome Parts
ES6: The Awesome PartsES6: The Awesome Parts
ES6: The Awesome Parts
 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your App
 
Webrtc mojo
Webrtc mojoWebrtc mojo
Webrtc mojo
 
Follow the White Rabbit - Message Queues with PHP
Follow the White Rabbit - Message Queues with PHPFollow the White Rabbit - Message Queues with PHP
Follow the White Rabbit - Message Queues with PHP
 
Using ngx_lua in UPYUN
Using ngx_lua in UPYUNUsing ngx_lua in UPYUN
Using ngx_lua in UPYUN
 
8 Minutes On Rack
8 Minutes On Rack8 Minutes On Rack
8 Minutes On Rack
 
And now you have two problems. Ruby regular expressions for fun and profit by...
And now you have two problems. Ruby regular expressions for fun and profit by...And now you have two problems. Ruby regular expressions for fun and profit by...
And now you have two problems. Ruby regular expressions for fun and profit by...
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
 
Testing Backbone applications with Jasmine
Testing Backbone applications with JasmineTesting Backbone applications with Jasmine
Testing Backbone applications with Jasmine
 
Docker & CoreOS at Utah Gophers
Docker & CoreOS at Utah GophersDocker & CoreOS at Utah Gophers
Docker & CoreOS at Utah Gophers
 
Testing Javascript with Jasmine
Testing Javascript with JasmineTesting Javascript with Jasmine
Testing Javascript with Jasmine
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
What’s new in ECMAScript 6.0
What’s new in ECMAScript 6.0What’s new in ECMAScript 6.0
What’s new in ECMAScript 6.0
 
Real time server
Real time serverReal time server
Real time server
 
Running a Scalable And Reliable Symfony2 Application in Cloud (Symfony Sweden...
Running a Scalable And Reliable Symfony2 Application in Cloud (Symfony Sweden...Running a Scalable And Reliable Symfony2 Application in Cloud (Symfony Sweden...
Running a Scalable And Reliable Symfony2 Application in Cloud (Symfony Sweden...
 

Similar to Writing Redis in Python with asyncio

Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
Wesley Beary
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
Nick Sieger
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
Ben Lin
 
Torquebox OSCON Java 2011
Torquebox OSCON Java 2011Torquebox OSCON Java 2011
Torquebox OSCON Java 2011
tobiascrawley
 

Similar to Writing Redis in Python with asyncio (20)

Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Fabric Python Lib
Fabric Python LibFabric Python Lib
Fabric Python Lib
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
 
Node.js - async for the rest of us.
Node.js - async for the rest of us.Node.js - async for the rest of us.
Node.js - async for the rest of us.
 
Play vs Rails
Play vs RailsPlay vs Rails
Play vs Rails
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
 
Crossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end FrameworkCrossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end Framework
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
 
Torquebox OSCON Java 2011
Torquebox OSCON Java 2011Torquebox OSCON Java 2011
Torquebox OSCON Java 2011
 
IBM Cloud University: Build, Deploy and Scale Node.js Microservices
IBM Cloud University: Build, Deploy and Scale Node.js MicroservicesIBM Cloud University: Build, Deploy and Scale Node.js Microservices
IBM Cloud University: Build, Deploy and Scale Node.js Microservices
 
Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)
Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)
Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)
 
JRuby with Java Code in Data Processing World
JRuby with Java Code in Data Processing WorldJRuby with Java Code in Data Processing World
JRuby with Java Code in Data Processing World
 
Node Interactive: Node.js Performance and Highly Scalable Micro-Services
Node Interactive: Node.js Performance and Highly Scalable Micro-ServicesNode Interactive: Node.js Performance and Highly Scalable Micro-Services
Node Interactive: Node.js Performance and Highly Scalable Micro-Services
 
CouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 HourCouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 Hour
 
Container (Docker) Orchestration Tools
Container (Docker) Orchestration ToolsContainer (Docker) Orchestration Tools
Container (Docker) Orchestration Tools
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
An intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECSAn intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECS
 
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
 
Step into serverless into the box 2018
Step into serverless into the box 2018Step into serverless into the box 2018
Step into serverless into the box 2018
 

Recently uploaded

Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Recently uploaded (20)

Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 

Writing Redis in Python with asyncio