Updated patcher.monkey_patch so it was easier to implement the util usecases. Deprecated everything in util that wasn't already deprecated.

This commit is contained in:
Ryan Williams
2010-02-09 13:11:20 -08:00
parent 57f2960884
commit 13046f4c4d
3 changed files with 71 additions and 98 deletions

View File

@@ -42,8 +42,12 @@ Monkeypatching the Standard Library
The other way of greening an application is simply to monkeypatch the standard The other way of greening an application is simply to monkeypatch the standard
library. This has the disadvantage of appearing quite magical, but the advantage of avoiding the late-binding problem. library. This has the disadvantage of appearing quite magical, but the advantage of avoiding the late-binding problem.
.. function:: eventlet.patcher.monkey_patch(os=True, select=True, socket=True, thread=True, time=True) .. function:: eventlet.patcher.monkey_patch(all=True, os=False, select=False, socket=False, thread=False, time=False):
By default, this function monkeypatches the key system modules by replacing their key elements with green equivalents. The keyword arguments afford some control over which modules are patched, in case that's important. If *all* is True, then all modules are patched regardless of the other arguments. If it's False, then the rest of the keyword arguments control patching of specific subsections of the standard library. Most patch the single module of the same name (e.g. time=True means that the time module is patched [time.sleep is patched by eventlet.sleep]). The exceptions to this rule are *socket*, which also patches the :mod:`ssl` module if present; and *thread*, which patches :mod:`thread`, :mod:`threading`, and :mod:`Queue`.
By default, this function monkeypatches the key system modules by replacing their key elements with green equivalents. The keyword arguments afford some control over which modules are patched, in case that's important. For almost all of them, they patch the single module of the same name (e.g. time=True means that the time module is patched [time.sleep is patched by eventlet.sleep]). The exceptions to this rule are *socket*, which also patches the :mod:`ssl` module if present; and *thread*, which patches both :mod:`thread` and :mod:`Queue`. Here's an example of using monkey_patch to patch only a few modules::
It is important to call :func:`eventlet.patcher.monkey_patch` as early in the lifetime of the application as possible. Try to do it as one of the first lines in the main module. The reason for this is that sometimes there is a class that inherits from a class that needs to be greened -- e.g. a class that inherits from socket.socket -- and inheritance is done at import time, so therefore the monkeypatching should happen before the module that has the derived class is imported. from eventlet import patcher
patcher.monkey_patch(all=False, socket=True, select=True)
It is important to call :func:`eventlet.patcher.monkey_patch` as early in the lifetime of the application as possible. Try to do it as one of the first lines in the main module. The reason for this is that sometimes there is a class that inherits from a class that needs to be greened -- e.g. a class that inherits from socket.socket -- and inheritance is done at import time, so therefore the monkeypatching should happen before the derived class is defined. It's safe to call monkey_patch multiple times.

View File

@@ -97,26 +97,38 @@ def patch_function(func, *additional_modules):
del sys.modules[name] del sys.modules[name]
return patched return patched
already_patched = {}
def monkey_patch(os=True, select=True, socket=True, thread=True, time=True): def monkey_patch(all=True, os=False, select=False,
socket=False, thread=False, time=False):
"""Globally patches certain system modules to be greenthread-friendly. """Globally patches certain system modules to be greenthread-friendly.
The keyword arguments afford some control over which modules are patched. The keyword arguments afford some control over which modules are patched.
For almost all of them, they patch the single module of the same name. The If *all* is True, then all modules are patched regardless of the other
exceptions are socket, which also patches the ssl module if present; and arguments. If it's False, then the rest of the keyword arguments control
thread, which patches thread and Queue. patching of specific subsections of the standard library.
Most patch the single module of the same name (os, time,
select). The exceptions are socket, which also patches the ssl module if
present; and thread, which patches thread, threading, and Queue.
It's safe to call monkey_patch multiple times.
""" """
modules_to_patch = [] modules_to_patch = []
if os: if all or os and not already_patched.get('os'):
modules_to_patch += _green_os_modules() modules_to_patch += _green_os_modules()
if select: already_patched['os'] = True
if all or select and not already_patched.get('select'):
modules_to_patch += _green_select_modules() modules_to_patch += _green_select_modules()
if socket: already_patched['select'] = True
if all or socket and not already_patched.get('socket'):
modules_to_patch += _green_socket_modules() modules_to_patch += _green_socket_modules()
if thread: already_patched['socket'] = True
if all or thread and not already_patched.get('thread'):
modules_to_patch += _green_thread_modules() modules_to_patch += _green_thread_modules()
if time: already_patched['thread'] = True
if all or time and not already_patched.get('time'):
modules_to_patch += _green_time_modules() modules_to_patch += _green_time_modules()
already_patched['time'] = True
for name, mod in modules_to_patch: for name, mod in modules_to_patch:
for attr in mod.__patched__: for attr in mod.__patched__:
patched_attr = getattr(mod, attr, None) patched_attr = getattr(mod, attr, None)

View File

@@ -2,10 +2,13 @@ import os
import select import select
import socket import socket
import errno import errno
import warnings
from eventlet import greenio from eventlet import greenio
def g_log(*args): def g_log(*args):
warnings.warn("eventlet.util.g_log is deprecated because we're pretty sure no one uses it. Send mail to eventletdev@lists.secondlife.com if you are actually using it.",
DeprecationWarning, stacklevel=2)
import sys import sys
from eventlet.support import greenlets as greenlet from eventlet.support import greenlets as greenlet
g_id = id(greenlet.getcurrent()) g_id = id(greenlet.getcurrent())
@@ -23,17 +26,11 @@ def g_log(*args):
__original_socket__ = socket.socket __original_socket__ = socket.socket
__original_gethostbyname__ = socket.gethostbyname
__original_getaddrinfo__ = socket.getaddrinfo
try:
__original_fromfd__ = socket.fromfd
__original_fork__ = os.fork
except AttributeError:
# Windows
__original_fromfd__ = None
__original_fork__ = None
def tcp_socket(): def tcp_socket():
warnings.warn("eventlet.util.tcp_sockt is deprecated."
"Please use the standard socket technique for this instead:"
"sock = socket.socket()",
DeprecationWarning, stacklevel=2)
s = __original_socket__(socket.AF_INET, socket.SOCK_STREAM) s = __original_socket__(socket.AF_INET, socket.SOCK_STREAM)
return s return s
@@ -68,81 +65,27 @@ except ImportError:
connection.set_connect_state() connection.set_connect_state()
return connection return connection
socket_already_wrapped = False
def wrap_socket_with_coroutine_socket(use_thread_pool=None): def wrap_socket_with_coroutine_socket(use_thread_pool=None):
global socket_already_wrapped warnings.warn("eventlet.util.wrap_socket_with_coroutine_socket() is now "
if socket_already_wrapped: "eventlet.patcher.monkey_patch(all=False, socket=True)",
return DeprecationWarning, stacklevel=2)
from eventlet import patcher
import eventlet.green.socket patcher.monkey_patch(all=False, socket=True)
socket.socket = eventlet.green.socket.socket
socket.ssl = eventlet.green.socket.ssl
try:
import ssl as _ssl
from eventlet.green import ssl
_ssl.wrap_socket = ssl.wrap_socket
except ImportError:
pass
if use_thread_pool is None:
# if caller doesn't specify, use the environment variable
# to decide whether to use tpool or not
use_thread_pool = os.environ.get("EVENTLET_TPOOL_GETHOSTBYNAME",
'').lower() == "yes"
if use_thread_pool:
try:
from eventlet import tpool
def new_gethostbyname(*args, **kw):
return tpool.execute(
__original_gethostbyname__, *args, **kw)
socket.gethostbyname = new_gethostbyname
def new_getaddrinfo(*args, **kw):
return tpool.execute(
__original_getaddrinfo__, *args, **kw)
socket.getaddrinfo = new_getaddrinfo
except ImportError:
pass # Windows
if __original_fromfd__ is not None:
def new_fromfd(*args, **kw):
return greenio.GreenSocket(__original_fromfd__(*args, **kw))
socket.fromfd = new_fromfd
socket_already_wrapped = True
__original_fdopen__ = os.fdopen
__original_read__ = os.read
__original_write__ = os.write
__original_waitpid__ = os.waitpid
## TODO wrappings for popen functions? not really needed since Process object exists?
pipes_already_wrapped = False
def wrap_pipes_with_coroutine_pipes(): def wrap_pipes_with_coroutine_pipes():
global pipes_already_wrapped warnings.warn("eventlet.util.wrap_pipes_with_coroutine_pipes() is now "
if pipes_already_wrapped: "eventlet.patcher.monkey_patch(all=False, os=True)",
return DeprecationWarning, stacklevel=2)
from eventlet.green import greenos from eventlet import patcher
os.fdopen = greenos.fdopen patcher.monkey_patch(all=False, os=True)
os.read = greenos.read
os.write = greenos.write
os.waitpid = greenos.waitpid
__original_select__ = select.select
def wrap_select_with_coroutine_select(): def wrap_select_with_coroutine_select():
from eventlet.green import select as greenselect warnings.warn("eventlet.util.wrap_select_with_coroutine_select() is now "
select.select = greenselect.select "eventlet.patcher.monkey_patch(all=False, select=True)",
DeprecationWarning, stacklevel=2)
from eventlet import patcher
try: patcher.monkey_patch(all=False, select=True)
import threading
__original_threadlocal__ = threading.local
except ImportError:
pass
def wrap_threading_local_with_coro_local(): def wrap_threading_local_with_coro_local():
""" """
@@ -150,12 +93,22 @@ def wrap_threading_local_with_coro_local():
Since greenlets cannot cross threads, so this should be semantically Since greenlets cannot cross threads, so this should be semantically
identical to ``threadlocal.local`` identical to ``threadlocal.local``
""" """
from eventlet import api warnings.warn("eventlet.util.wrap_threading_local_with_coro_local() is now "
from eventlet.corolocal import local "eventlet.patcher.monkey_patch(all=False, thread=True) -- though"
threading.local = local "note that more than just _local is patched now.",
DeprecationWarning, stacklevel=2)
from eventlet import patcher
patcher.monkey_patch(all=False, thread=True)
def socket_bind_and_listen(descriptor, addr=('', 0), backlog=50): def socket_bind_and_listen(descriptor, addr=('', 0), backlog=50):
warnings.warn("eventlet.util.socket_bind_and_listen is deprecated."
"Please use the standard socket methodology for this instead:"
"sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)"
"sock.bind(addr)"
"sock.listen(backlog)",
DeprecationWarning, stacklevel=2)
set_reuse_addr(descriptor) set_reuse_addr(descriptor)
descriptor.bind(addr) descriptor.bind(addr)
descriptor.listen(backlog) descriptor.listen(backlog)
@@ -163,6 +116,10 @@ def socket_bind_and_listen(descriptor, addr=('', 0), backlog=50):
def set_reuse_addr(descriptor): def set_reuse_addr(descriptor):
warnings.warn("eventlet.util.set_reuse_addr is deprecated."
"Please use the standard socket methodology for this instead:"
"sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)",
DeprecationWarning, stacklevel=2)
try: try:
descriptor.setsockopt( descriptor.setsockopt(
socket.SOL_SOCKET, socket.SOL_SOCKET,