线程本地Python打印
对于线程本地Python打印,python,python-multithreading,Python,Python Multithreading,对于print()和类似内容,是否有任何内置方法使不同的线程具有不同的目标 我正在探索创建一个交互式Python环境,因此我不能只使用模块spamegg中的print()。它必须是无参数的全局可用线程。您可以用检查当前线程并写入相应文件的对象替换sys.stdout: import sys, threading class CustomOutput(object): def __init__(self): # the "softspace" slot is used i
print()
和类似内容,是否有任何内置方法使不同的线程具有不同的目标
我正在探索创建一个交互式Python环境,因此我不能只使用模块spamegg中的
print()
。它必须是无参数的全局可用线程。您可以用检查当前线程并写入相应文件的对象替换sys.stdout
:
import sys, threading
class CustomOutput(object):
def __init__(self):
# the "softspace" slot is used internally by Python's print
# to keep track of whether to prepend space to the
# printed expression
self.softspace = 0
self._old_stdout = None
def activate(self):
self._old_stdout = sys.stdout
sys.stdout = self
def deactivate(self):
sys.stdout = self._old_stdout
self._old_stdout = None
def write(self, s):
# actually write to an open file obtained from an attribute
# on the current thread
threading.current_thread().open_file.write(s)
def writelines(self, seq):
for s in seq:
self.write(s)
def close(self):
pass
def flush(self):
pass
def isatty(self):
return False
我可能会给你们一个解决方案,但这比打印要复杂得多
class ClusteredLogging(object):
'''
Class gathers all logs performed inside with statement and flush
it to mainHandler on exit at once.
Good for multithreaded applications that has to log several
lines at once.
'''
def __init__(self, mainHandler, formatter):
self.mainHandler = mainHandler
self.formatter = formatter
self.buffer = StringIO()
self.handler = logging.StreamHandler(self.buffer)
self.handler.setFormatter(formatter)
def __enter__(self):
rootLogger = logging.getLogger()
rootLogger.addHandler(self.handler)
def __exit__(self, t, value, tb):
rootLogger = logging.getLogger()
rootLogger.removeHandler(self.handler)
self.handler.flush()
self.buffer.flush()
rootLogger.addHandler(self.mainHandler)
logging.info(self.buffer.getvalue().strip())
rootLogger.removeHandler(self.mainHandler)
使用此功能,您可以为每个线程创建日志处理程序,并将其配置为将日志存储到不同的位置
请记住,这是为了实现稍微不同的目标而开发的(请参阅注释),但您可以从ClusteredLogging的处理程序杂耍特性开始进行调整
还有一些测试代码:
import concurrent.futures
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
import logging
import sys
# put ClusteredLogging here
if __name__ == "__main__":
formatter = logging.Formatter('%(asctime)s %(levelname)8s\t%(message)s')
onlyMessageFormatter = logging.Formatter("%(message)s")
mainHandler = logging.StreamHandler(sys.stdout)
mainHandler.setFormatter(onlyMessageFormatter)
mainHandler.setLevel(logging.DEBUG)
rootLogger = logging.getLogger()
rootLogger.setLevel(logging.DEBUG)
def logSomethingLong(label):
with ClusteredLogging(mainHandler, formatter):
for i in range(15):
logging.info(label + " " + str(i))
labels = ("TEST", "EXPERIMENT", "TRIAL")
executor = concurrent.futures.ProcessPoolExecutor()
futures = [executor.submit(logSomethingLong, label) for label in labels]
concurrent.futures.wait(futures)
你可以按你的要求去做,尽管它很复杂,很笨重,可能不便于携带,我不认为这是你想要做的
您对仅使用spamegg.print
的异议是:
我正在探索创建一个交互式Python环境,因此我不能只使用模块spamegg
中的print()
。它必须是无参数的全局可用的
但解决方法很简单:只需在代码中使用modulespamegg
中的print
,在交互式解释器中使用spamegg导入print。就这些
就这一点而言,没有充分的理由将其称为print
。如果您的所有代码都使用了其他具有不同名称的输出函数,那么您可以在交互式解释器中执行相同的操作
但是如何让每个线程有不同的目的地呢 要做到这一点,最简单的方法就是在一个列表中查找目的地
但是如果你真的想用艰难的方式完成这两部分,你可以 要实现全局
打印
,您可以让spamegg
替换内置的打印
,而不只是给您一种阴影,或者让它替换sys.stdout
,这样带有默认参数的内置打印
将在其他地方打印
import builtins
_real_print = builtins.print
def _print(*args, **kwargs):
kwargs.setdefault('file', my_output_destination)
_real_print(*args, **kwargs)
builtins.print = _print
import io
import sys
class MyStdOut(io.TextIOBase):
# ... __init__, write, etc.
sys.stdout = MyStdOut()
这仍然需要使用线程本地目标
或者,您可以在自己的自定义globals
环境中编译或包装每个线程函数,该环境将替换默认的\uuuuuuu内置函数和/或sys
,允许您从一开始就为每个线程指定不同的函数。例如:
from functools import partial
from threading import Thread
from types import FunctionType
class MyThread(Thread):
def __init__(self, group=None, target=None, *args, **kwargs):
if target:
g = target.__globals__.copy()
g['__builtins__'] = g['__builtins__'].copy()
output = make_output_for_new_thread()
g['__builtins__']['print'] = partial(print, file=output)
target = FunctionType(thread_func.__code__, g, thread_func.__name__,
thread_func.__defaults__, thread_func.__closure__)
super().__init__(self, group, target, *args, **kwargs)
你说的“无参数的全球可用的”是什么意思?全局可用的print
函数接受0个或多个参数。您也可以轻松地定义另一个执行相同操作的print
函数。(除非您使用的是Python2.x,而不是使用来自未来导入打印功能的,在这种情况下,print
首先不是一个函数,它是一种特殊的语句,您根本无法替换它。)同时,如果您想要不同的目的地,可以通过替换sys.stdout
,来实现这一点,但这是一个全球性的sys
,因此没有帮助。您几乎必须创建一些名称空间(可能是一个模块,但可能是一个假内置或exec
上下文,或者在不了解更多设计的情况下,谁知道会发生什么…)其中包含print
函数。@abarnert不使用print(…,file=spamegg)
如果您对它的用处有任何评论,我将不胜感激。