# Copyright (C) 2010, 2011 Sebastian Thiel (byronimo@gmail.com) and contributors
#
# This module is part of async and is released under
# the New BSD License: http://www.opensource.org/licenses/bsd-license.php
"""Module with utilities related to async operations"""
from threading import (
Lock,
_allocate_lock,
_time,
)
try:
from queue import Empty
except ImportError:
from Queue import Empty
from collections import deque
import sys
import os
import time
#{ Routines
def cpu_count():
""":return:number of CPUs in the system
:note: inspired by multiprocessing"""
num = 0
try:
if sys.platform == 'win32':
num = int(os.environ['NUMBER_OF_PROCESSORS'])
elif 'bsd' in sys.platform or sys.platform == 'darwin':
num = int(os.popen('sysctl -n hw.ncpu').read())
else:
num = os.sysconf('SC_NPROCESSORS_ONLN')
except (ValueError, KeyError, OSError, AttributeError):
pass
# END exception handling
if num == 0:
raise NotImplementedError('cannot determine number of cpus')
return num
#} END routines
class DummyLock(object):
"""An object providing a do-nothing lock interface for use in sync mode"""
__slots__ = tuple()
def acquire(self):
pass
def release(self):
pass
class SyncQueue(deque):
"""Adapter to allow using a deque like a queue, without locking"""
def get(self, block=True, timeout=None):
try:
return self.popleft()
except IndexError:
raise Empty
# END raise empty
def empty(self):
return len(self) == 0
def set_writable(self, state):
pass
def writable(self):
return True
def put(self, item, block=True, timeout=None):
self.append(item)
class HSCondition(deque):
"""Cleaned up code of the original condition object in order
to make it run and respond faster."""
__slots__ = ("_lock")
delay = 0.0002 # reduces wait times, but increases overhead
def __init__(self, lock=None):
if lock is None:
lock = Lock()
self._lock = lock
def release(self):
self._lock.release()
def acquire(self, block=None):
if block is None:
self._lock.acquire()
else:
self._lock.acquire(block)
def wait(self, timeout=None):
waiter = _allocate_lock()
waiter.acquire() # get it the first time, no blocking
self.append(waiter)
try:
# restore state no matter what (e.g., KeyboardInterrupt)
# now we block, as we hold the lock already
# in the momemnt we release our lock, someone else might actually resume
self._lock.release()
if timeout is None:
waiter.acquire()
else:
# Balancing act: We can't afford a pure busy loop, because of the
# GIL, so we have to sleep
# We try to sleep only tiny amounts of time though to be very responsive
# NOTE: this branch is not used by the async system anyway, but
# will be hit when the user reads with timeout
endtime = _time() + timeout
delay = self.delay
acquire = waiter.acquire
while True:
gotit = acquire(0)
if gotit:
break
remaining = endtime - _time()
if remaining