我一直在尝试使用python threading api。 我有这个代码适用于我想要实现的目标:---->在调用python线程上运行之前执行函数。
但是为了做到这一点,我总是必须在run()方法中调用time.sleep(1)使其继续执行execute()。否则线程退出而不进行函数赋值和执行。是否有更好的方法实现这种等待?
from __future__ import print_function
import threading
import time
import functools
import contextlib
import thread
from threading import Lock
#import contextlib
#Thread module for dealing with lower level thread operations.Thread is limited use Threading instead.
def timeit(fn):
'''Timeit function like this doesnot work with the thread calls'''
def wrapper(*args,**kwargs):
start = time.time()
fn(*args,**kwargs)
end = time.time()
threadID = ""
print ("Duration for func %s :%d\n"%(fn.__name__ +"_"+ threading.current_thread().name ,end-start))
return wrapper
exitFlag = 0
@timeit
def print_time(counter,delay):
while counter:
if exitFlag:
thread.exit()
time.sleep(delay)
print("%s : %s_%d"%(threading.current_thread().name,time.ctime(time.time()),counter))
counter -= 1
class Mythread(threading.Thread):
def __init__(self,threadID,name):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self._f = None
def run(self):
print("Starting%s\n" % self.name)
time.sleep(1)
if self._f:
self._f()
print("Exiting%s\n" % self.name)
else:
print("Exiting%s without function execution\n" % self.name )
# def set_f(self,f):
# self._f = f
def execute(self,f,*args,**kwargs):
self._f=functools.partial(f,*args,**kwargs)
def __enter__(self):
self.start()
def __exit__(self,type,value,traceback):
self.join()
class ThreadContainer(object):
def __init__(self,id,name):
self._t = Mythread(id,name)
def execute(self,f,*args,**kwargs):
self._f=functools.partial(f,*args,**kwargs)
self._t.set_f(self._f)
# self._t.start()
# self._t.join()
def __enter__(self):
self._t.start()
def __exit__(self,type,value,traceback):
self._t.join()
if __name__ == '__main__':
'''
print_time(5, 1)
threadLock = threading.Lock()
threads = []
thread1 = Mythread(1,"Thread1",5,1)
thread2 = Mythread(2,"Thread2",5,2)
thread1.start()
thread2.start()
threads.append(thread1)
threads.append(thread2)
for t in threads:
t.join()
'''
# thread1 = Mythread(1,"Thread1")
# thread2 = Mythread(2,"Thread2")
# with contextlib.nested(ThreadContainer(1,"Thread1"),ThreadContainer(2,"Thread2")) as (t1,t2):
# t1.execute(print_time,5,1)
# t2.execute(print_time,5,2)
t1 = Mythread(1,"Thread1")
t2 = Mythread(2,"Thread2")
with contextlib.nested(t1,t2):
t1.execute(print_time,5,1)
t2.execute(print_time,5,2)
print("Exiting main thread ")
答案 0 :(得分:1)
这里的问题是你希望run
函数等到调用execute
函数。
当然,显而易见的解决方案是在致电execute
之前致电start
:
t1.execute(print_time,5,1)
t2.execute(print_time,5,2)
with contextlib.nested(t1, t2):
pass
...或只是调用execute
来调用start
,或者将函数传递给构造函数或start
调用,或者......
此外,您的设计有点奇怪。线程函数旨在处理尚未设置_f
的情况......但是您希望它等到设置_f
之后?
但可以想象,这种问题可能会出现在更现实的设计中,所以,让我们来看看如何解决它。
首先,添加sleep
来解决线程问题几乎总是表明你做错了。这也是导致可怕的性能问题的好方法(例如:当你在足够的地方添加足够的sleep
以使一切都工作时,你的应用程序需要30秒而不是30毫秒) - 更糟糕的是,竞争条件错误(肯定1秒总是足够的时间,对吗?除非计算机正在颠倒交换,或从休眠状态唤醒,或忙于使用所有CPU的其他程序,或......)。
如果您尝试跨线程同步操作,则需要使用同步对象。诀窍是知道正确的。阅读Lock
至Event
的文档(以及3.x添加Barrier
),并查找有关线程的教程,以便更全面地了解所有这些内容的用途。 *
在这种情况下,您已经有了等待对保存状态进行某些更改的代码,以及正在进行更改的其他代码,这是'Condition'的原型用例。所以:
class Mythread(threading.Thread):
def __init__(self, threadID, name, condition):
self.condition = condition
# ... same as before
def run(self):
# ... setup before checking for _f
with self.condition:
while not self._f:
self.condition.wait()
self._f()
# ... anything else you want
现在,您需要创建Condition
,将其传递给线程,然后notify
。
您可以使用一个Condition
:
condition = threading.Condition()
t1 = Mythread(1, "Thread1", condition)
t2 = Mythread(2, "Thread2", condition)
with contextlib.nested(t1,t2):
with condition:
t1.execute(print_time, 5, 1)
t2.execute(print_time, 5, 2)
condition.notify_all()
或者,您可以为每个帖子提供自己的Condition
:
class Mythread(threading.Thread):
def __init__(self, threadID, name):
self.condition = Condition()
# ... same as before
# ...
t1 = Mythread(1, "Thread1")
t2 = Mythread(2, "Thread2")
with contextlib.nested(t1,t2):
with t1.condition:
t1.execute(print_time, 5, 1)
t1.condition.notify()
with t2.condition:
t2.execute(print_time, 5, 1)
t2.condition.notify()
请注意,这不允许您明确“未设置”_f
,但这样做很容易。例如,您可以添加_f_set
属性,然后检查该属性而不是_f
,以便有人可以致电execute(None)
(然后notify
)来唤醒您并获取到“不_f
”的情况。
*警告:某些命名不一致。有一个不同的东西也被称为“障碍”,一个不同的东西也被称为“围栏”,并且有很多“事件”的变体与蟒蛇有很大不同(其中一些更像是条件,但不是实际上可以这样使用),有时“条件变量”是由同步对象而不是同步对象保护的实际共享状态,依此类推......