SlideShare a Scribd company logo
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
Writing Redis in Python with asyncio
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
Writing Redis in Python with asyncio
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
Writing Redis in Python with asyncio
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
Ad

Recommended

Introduction to Nodejs
Introduction to Nodejs
Gabriele Lana
 
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015
Fernando Hamasaki de Amorim
 
What's New in ES6 for Web Devs
What's New in ES6 for Web Devs
Rami Sayar
 
Symfony2 Service Container: Inject me, my friend
Symfony2 Service Container: Inject me, my friend
Kirill Chebunin
 
AnyMQ, Hippie, and the real-time web
AnyMQ, Hippie, and the real-time web
clkao
 
Workshop 10: ECMAScript 6
Workshop 10: ECMAScript 6
Visual Engineering
 
Unit Testing Express Middleware
Unit Testing Express Middleware
Morris Singer
 
Trading with opensource tools, two years later
Trading with opensource tools, two years later
clkao
 
node.js practical guide to serverside javascript
node.js practical guide to serverside javascript
Eldar Djafarov
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
Node.js API 서버 성능 개선기
Node.js API 서버 성능 개선기
JeongHun Byeon
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf Conference
 
Practical Testing of Ruby Core
Practical Testing of Ruby Core
Hiroshi SHIBATA
 
ES6: The Awesome Parts
ES6: The Awesome Parts
Domenic Denicola
 
A Little Backbone For Your App
A Little Backbone For Your App
Luca Mearelli
 
Webrtc mojo
Webrtc mojo
bpmedley
 
Follow the White Rabbit - Message Queues with PHP
Follow the White Rabbit - Message Queues with PHP
Eric Rodriguez (Hiring in Lex)
 
Using ngx_lua in UPYUN
Using ngx_lua in UPYUN
Cong Zhang
 
8 Minutes On Rack
8 Minutes On Rack
danwrong
 
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...
Codemotion
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016
Manoj Kumar
 
Testing Backbone applications with Jasmine
Testing Backbone applications with Jasmine
Leon van der Grient
 
Docker & CoreOS at Utah Gophers
Docker & CoreOS at Utah Gophers
Josh Braegger
 
Testing Javascript with Jasmine
Testing Javascript with Jasmine
Tim Tyrrell
 
Advanced symfony Techniques
Advanced symfony Techniques
Kris Wallsmith
 
What’s new in ECMAScript 6.0
What’s new in ECMAScript 6.0
Eyal Vardi
 
Real time server
Real time server
thepian
 
Running a Scalable And Reliable Symfony2 Application in Cloud (Symfony Sweden...
Running a Scalable And Reliable Symfony2 Application in Cloud (Symfony Sweden...
Ville Mattila
 
Writing robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
Fabric Python Lib
Fabric Python Lib
Simone Federici
 

More Related Content

What's hot (20)

node.js practical guide to serverside javascript
node.js practical guide to serverside javascript
Eldar Djafarov
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
Node.js API 서버 성능 개선기
Node.js API 서버 성능 개선기
JeongHun Byeon
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf Conference
 
Practical Testing of Ruby Core
Practical Testing of Ruby Core
Hiroshi SHIBATA
 
ES6: The Awesome Parts
ES6: The Awesome Parts
Domenic Denicola
 
A Little Backbone For Your App
A Little Backbone For Your App
Luca Mearelli
 
Webrtc mojo
Webrtc mojo
bpmedley
 
Follow the White Rabbit - Message Queues with PHP
Follow the White Rabbit - Message Queues with PHP
Eric Rodriguez (Hiring in Lex)
 
Using ngx_lua in UPYUN
Using ngx_lua in UPYUN
Cong Zhang
 
8 Minutes On Rack
8 Minutes On Rack
danwrong
 
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...
Codemotion
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016
Manoj Kumar
 
Testing Backbone applications with Jasmine
Testing Backbone applications with Jasmine
Leon van der Grient
 
Docker & CoreOS at Utah Gophers
Docker & CoreOS at Utah Gophers
Josh Braegger
 
Testing Javascript with Jasmine
Testing Javascript with Jasmine
Tim Tyrrell
 
Advanced symfony Techniques
Advanced symfony Techniques
Kris Wallsmith
 
What’s new in ECMAScript 6.0
What’s new in ECMAScript 6.0
Eyal Vardi
 
Real time server
Real time server
thepian
 
Running a Scalable And Reliable Symfony2 Application in Cloud (Symfony Sweden...
Running a Scalable And Reliable Symfony2 Application in Cloud (Symfony Sweden...
Ville Mattila
 
node.js practical guide to serverside javascript
node.js practical guide to serverside javascript
Eldar Djafarov
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
Node.js API 서버 성능 개선기
Node.js API 서버 성능 개선기
JeongHun Byeon
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf Conference
 
Practical Testing of Ruby Core
Practical Testing of Ruby Core
Hiroshi SHIBATA
 
A Little Backbone For Your App
A Little Backbone For Your App
Luca Mearelli
 
Webrtc mojo
Webrtc mojo
bpmedley
 
Using ngx_lua in UPYUN
Using ngx_lua in UPYUN
Cong Zhang
 
8 Minutes On Rack
8 Minutes On Rack
danwrong
 
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...
Codemotion
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016
Manoj Kumar
 
Testing Backbone applications with Jasmine
Testing Backbone applications with Jasmine
Leon van der Grient
 
Docker & CoreOS at Utah Gophers
Docker & CoreOS at Utah Gophers
Josh Braegger
 
Testing Javascript with Jasmine
Testing Javascript with Jasmine
Tim Tyrrell
 
Advanced symfony Techniques
Advanced symfony Techniques
Kris Wallsmith
 
What’s new in ECMAScript 6.0
What’s new in ECMAScript 6.0
Eyal Vardi
 
Real time server
Real time server
thepian
 
Running a Scalable And Reliable Symfony2 Application in Cloud (Symfony Sweden...
Running a Scalable And Reliable Symfony2 Application in Cloud (Symfony Sweden...
Ville Mattila
 

Similar to Writing Redis in Python with asyncio (20)

Writing robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
Fabric Python Lib
Fabric Python Lib
Simone Federici
 
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
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
Wesley Beary
 
Node.js - async for the rest of us.
Node.js - async for the rest of us.
Mike Brevoort
 
Play vs Rails
Play vs Rails
Daniel Cukier
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
Nick Sieger
 
Crossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end Framework
Daniel Spector
 
How 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 2011
tobiascrawley
 
IBM Cloud University: Build, Deploy and Scale Node.js Microservices
IBM Cloud University: Build, Deploy and Scale Node.js Microservices
Chris Bailey
 
Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)
Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)
Brian Sam-Bodden
 
JRuby with Java Code in Data Processing World
JRuby with Java Code in Data Processing World
SATOSHI TAGOMORI
 
Node Interactive: Node.js Performance and Highly Scalable Micro-Services
Node Interactive: Node.js Performance and Highly Scalable Micro-Services
Chris Bailey
 
CouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 Hour
Peter Friese
 
Container (Docker) Orchestration Tools
Container (Docker) Orchestration Tools
Dhilipsiva DS
 
Play!ng with scala
Play!ng with scala
Siarzh Miadzvedzeu
 
SW Security Lec4 Securing architecture.pptx
SW Security Lec4 Securing architecture.pptx
KhalidShawky1
 
An intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECS
Yevgeniy Brikman
 
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...
bobmcwhirter
 
Writing 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)
Wesley Beary
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
Wesley Beary
 
Node.js - async for the rest of us.
Node.js - async for the rest of us.
Mike Brevoort
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
Nick Sieger
 
Crossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end Framework
Daniel Spector
 
How 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 2011
tobiascrawley
 
IBM Cloud University: Build, Deploy and Scale Node.js Microservices
IBM Cloud University: Build, Deploy and Scale Node.js Microservices
Chris Bailey
 
Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)
Server-Side Push: Comet, Web Sockets come of age (OSCON 2013)
Brian Sam-Bodden
 
JRuby with Java Code in Data Processing World
JRuby with Java Code in Data Processing World
SATOSHI TAGOMORI
 
Node Interactive: Node.js Performance and Highly Scalable Micro-Services
Node Interactive: Node.js Performance and Highly Scalable Micro-Services
Chris Bailey
 
CouchDB Mobile - From Couch to 5K in 1 Hour
CouchDB Mobile - From Couch to 5K in 1 Hour
Peter Friese
 
Container (Docker) Orchestration Tools
Container (Docker) Orchestration Tools
Dhilipsiva DS
 
SW Security Lec4 Securing architecture.pptx
SW Security Lec4 Securing architecture.pptx
KhalidShawky1
 
An intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECS
Yevgeniy Brikman
 
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...
bobmcwhirter
 
Ad

Recently uploaded (20)

Tech-ASan: Two-stage check for Address Sanitizer - Yixuan Cao.pdf
Tech-ASan: Two-stage check for Address Sanitizer - Yixuan Cao.pdf
caoyixuan2019
 
"How to survive Black Friday: preparing e-commerce for a peak season", Yurii ...
"How to survive Black Friday: preparing e-commerce for a peak season", Yurii ...
Fwdays
 
10 Key Challenges for AI within the EU Data Protection Framework.pdf
10 Key Challenges for AI within the EU Data Protection Framework.pdf
Priyanka Aash
 
Connecting Data and Intelligence: The Role of FME in Machine Learning
Connecting Data and Intelligence: The Role of FME in Machine Learning
Safe Software
 
Enhance GitHub Copilot using MCP - Enterprise version.pdf
Enhance GitHub Copilot using MCP - Enterprise version.pdf
Nilesh Gule
 
Cyber Defense Matrix Workshop - RSA Conference
Cyber Defense Matrix Workshop - RSA Conference
Priyanka Aash
 
AI VIDEO MAGAZINE - June 2025 - r/aivideo
AI VIDEO MAGAZINE - June 2025 - r/aivideo
1pcity Studios, Inc
 
Lessons Learned from Developing Secure AI Workflows.pdf
Lessons Learned from Developing Secure AI Workflows.pdf
Priyanka Aash
 
From Manual to Auto Searching- FME in the Driver's Seat
From Manual to Auto Searching- FME in the Driver's Seat
Safe Software
 
Raman Bhaumik - Passionate Tech Enthusiast
Raman Bhaumik - Passionate Tech Enthusiast
Raman Bhaumik
 
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance
 
FIDO Seminar: Perspectives on Passkeys & Consumer Adoption.pptx
FIDO Seminar: Perspectives on Passkeys & Consumer Adoption.pptx
FIDO Alliance
 
GenAI Opportunities and Challenges - Where 370 Enterprises Are Focusing Now.pdf
GenAI Opportunities and Challenges - Where 370 Enterprises Are Focusing Now.pdf
Priyanka Aash
 
CapCut Pro Crack For PC Latest Version {Fully Unlocked} 2025
CapCut Pro Crack For PC Latest Version {Fully Unlocked} 2025
pcprocore
 
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC
 
ReSTIR [DI]: Spatiotemporal reservoir resampling for real-time ray tracing ...
ReSTIR [DI]: Spatiotemporal reservoir resampling for real-time ray tracing ...
revolcs10
 
Smarter Aviation Data Management: Lessons from Swedavia Airports and Sweco
Smarter Aviation Data Management: Lessons from Swedavia Airports and Sweco
Safe Software
 
"Database isolation: how we deal with hundreds of direct connections to the d...
"Database isolation: how we deal with hundreds of direct connections to the d...
Fwdays
 
FIDO Seminar: New Data: Passkey Adoption in the Workforce.pptx
FIDO Seminar: New Data: Passkey Adoption in the Workforce.pptx
FIDO Alliance
 
Creating Inclusive Digital Learning with AI: A Smarter, Fairer Future
Creating Inclusive Digital Learning with AI: A Smarter, Fairer Future
Impelsys Inc.
 
Tech-ASan: Two-stage check for Address Sanitizer - Yixuan Cao.pdf
Tech-ASan: Two-stage check for Address Sanitizer - Yixuan Cao.pdf
caoyixuan2019
 
"How to survive Black Friday: preparing e-commerce for a peak season", Yurii ...
"How to survive Black Friday: preparing e-commerce for a peak season", Yurii ...
Fwdays
 
10 Key Challenges for AI within the EU Data Protection Framework.pdf
10 Key Challenges for AI within the EU Data Protection Framework.pdf
Priyanka Aash
 
Connecting Data and Intelligence: The Role of FME in Machine Learning
Connecting Data and Intelligence: The Role of FME in Machine Learning
Safe Software
 
Enhance GitHub Copilot using MCP - Enterprise version.pdf
Enhance GitHub Copilot using MCP - Enterprise version.pdf
Nilesh Gule
 
Cyber Defense Matrix Workshop - RSA Conference
Cyber Defense Matrix Workshop - RSA Conference
Priyanka Aash
 
AI VIDEO MAGAZINE - June 2025 - r/aivideo
AI VIDEO MAGAZINE - June 2025 - r/aivideo
1pcity Studios, Inc
 
Lessons Learned from Developing Secure AI Workflows.pdf
Lessons Learned from Developing Secure AI Workflows.pdf
Priyanka Aash
 
From Manual to Auto Searching- FME in the Driver's Seat
From Manual to Auto Searching- FME in the Driver's Seat
Safe Software
 
Raman Bhaumik - Passionate Tech Enthusiast
Raman Bhaumik - Passionate Tech Enthusiast
Raman Bhaumik
 
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance
 
FIDO Seminar: Perspectives on Passkeys & Consumer Adoption.pptx
FIDO Seminar: Perspectives on Passkeys & Consumer Adoption.pptx
FIDO Alliance
 
GenAI Opportunities and Challenges - Where 370 Enterprises Are Focusing Now.pdf
GenAI Opportunities and Challenges - Where 370 Enterprises Are Focusing Now.pdf
Priyanka Aash
 
CapCut Pro Crack For PC Latest Version {Fully Unlocked} 2025
CapCut Pro Crack For PC Latest Version {Fully Unlocked} 2025
pcprocore
 
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC
 
ReSTIR [DI]: Spatiotemporal reservoir resampling for real-time ray tracing ...
ReSTIR [DI]: Spatiotemporal reservoir resampling for real-time ray tracing ...
revolcs10
 
Smarter Aviation Data Management: Lessons from Swedavia Airports and Sweco
Smarter Aviation Data Management: Lessons from Swedavia Airports and Sweco
Safe Software
 
"Database isolation: how we deal with hundreds of direct connections to the d...
"Database isolation: how we deal with hundreds of direct connections to the d...
Fwdays
 
FIDO Seminar: New Data: Passkey Adoption in the Workforce.pptx
FIDO Seminar: New Data: Passkey Adoption in the Workforce.pptx
FIDO Alliance
 
Creating Inclusive Digital Learning with AI: A Smarter, Fairer Future
Creating Inclusive Digital Learning with AI: A Smarter, Fairer Future
Impelsys Inc.
 
Ad

Writing Redis in Python with asyncio