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 javascriptEldar Djafarov
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
Node.js API 서버 성능 개선기
Node.js API 서버 성능 개선기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 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 CorePractical Testing of Ruby Core
Practical Testing of Ruby CoreHiroshi SHIBATA
 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your AppLuca Mearelli
 
Webrtc mojo
Webrtc mojoWebrtc mojo
Webrtc mojobpmedley
 
Using ngx_lua in UPYUN
Using ngx_lua in UPYUNUsing ngx_lua in UPYUN
Using ngx_lua in UPYUNCong Zhang
 
8 Minutes On Rack
8 Minutes On Rack8 Minutes On Rack
8 Minutes On Rackdanwrong
 
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...Codemotion
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016Manoj Kumar
 
Testing Backbone applications with Jasmine
Testing Backbone applications with JasmineTesting Backbone applications with Jasmine
Testing Backbone applications with JasmineLeon van der Grient
 
Docker & CoreOS at Utah Gophers
Docker & CoreOS at Utah GophersDocker & CoreOS at Utah Gophers
Docker & CoreOS at Utah GophersJosh Braegger
 
Testing Javascript with Jasmine
Testing Javascript with JasmineTesting Javascript with Jasmine
Testing Javascript with JasmineTim Tyrrell
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
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.0Eyal Vardi
 
Real time server
Real time serverReal time server
Real time serverthepian
 
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...Ville Mattila
 

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 applicationsTom 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
 
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 CloudWesley Beary
 
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.Mike Brevoort
 
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 2011Nick Sieger
 
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 FrameworkDaniel Spector
 
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 frameworkBen Lin
 
Torquebox OSCON Java 2011
Torquebox OSCON Java 2011Torquebox OSCON Java 2011
Torquebox OSCON Java 2011tobiascrawley
 
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 MicroservicesChris Bailey
 
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)Brian Sam-Bodden
 
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 WorldSATOSHI TAGOMORI
 
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-ServicesChris Bailey
 
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 HourPeter Friese
 
Container (Docker) Orchestration Tools
Container (Docker) Orchestration ToolsContainer (Docker) Orchestration Tools
Container (Docker) Orchestration ToolsDhilipsiva DS
 
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 ECSYevgeniy 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...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
 
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 2018Ortus Solutions, Corp
 

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

Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsSnow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsHyundai Motor Group
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraDeakin University
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAndikSusilo4
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxnull - The Open Security Community
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 

Recently uploaded (20)

Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsSnow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning era
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & Application
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 

Writing Redis in Python with asyncio