随着句和线程:让运行前执行功能 [英] With-Statement and Threading :Making function execute before run

查看:138
本文介绍了随着句和线程:让运行前执行功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是由以下问题的后续行动: With语句和Python线程

我一直在尝试与Python线程API。
我有这个code这适用于什么我想要实现:Python的线程调用运行前---->函数执行

然而,要做到这一点,我总是要调用time.sleep(1)中的run()方法,使之继续执行(),否则该线程将退出无功能分配和execution.Is那里更好的方法实现这种类型的等待?

 从__future__进口print_function
进口螺纹
进口时间
进口functools
进口contextlib
进口螺纹
从进口螺纹锁
#进口contextlib
用于处理低级别的线程operations.Thread #Thread模块是有限的使用线程来代替。高清timeit(FN):
    '''Timeit功能像线程这不列入工作需要'''
    高清封装(* ARGS,** kwargs):
        开始=选定了time.time()
        FN(* ARGS,** kwargs)
        结束=选定了time.time()
        主题ID =
        打印(持续时间FUNC%S:%d个\\ N。%(FN .__ name__ +_+ threading.current_thread()的名称,最终开始))
    包装回报exitFlag = 0@timeit
高清print_time(计数器,延迟):
    而计数器:
        如果exitFlag:
            thread.exit()
        time.sleep(延迟)
        打印(%S:%S_%D。%(threading.current_thread()的名称,time.ctime(选定了time.time()),计数器))
        计数器 - = 1类MyThread的(threading.Thread):
    高清__init __(自我,主题ID,姓名):
        threading.Thread .__的init __(个体经营)
        self.threadID =主题ID
        self.name =名称
        self._f =无    DEF运行(个体经营):
        打印(启动%S \\ n%self.name)
        time.sleep(1)
        如果self._f:
            self._f()
            打印(退出%S \\ n%self.name)
        其他:
            打印(%self.name无函数执行\\ n退出%S)#高清set_f(个体经营,F):
#self._f = F    DEF执行(个体经营,F * ARGS,** kwargs):
        self._f = functools.partial(F,* ARGS,** kwargs)    高清__enter __(个体经营):
        self.start()    高清__exit __(自我,类型,值,追踪):
        self.join()
类ThreadContainer(对象):
    高清__init __(自我,编号,名称):
        self._t = MyThread的(ID,姓名)    DEF执行(个体经营,F * ARGS,** kwargs):
        self._f = functools.partial(F,* ARGS,** kwargs)
        self._t.set_f(self._f)
#self._t.start()
#self._t.join()
    高清__enter __(个体经营):
        self._t.start()    高清__exit __(自我,类型,值,追踪):
        self._t.join()
如果__name__ =='__main__':
    '''
    print_time(5,1)
     threadLock = threading.Lock()
     螺纹= []
     线程1 = MyThread的(1,线程1,5,1)
     线程2 = MyThread的(2,线程2,5,2)
     thread1.start()
     thread2.start()
     threads.append(线程1)
     threads.append(线程2)
     在主题T:
         t.join()
    '''
#线程1 = MyThread的(1,线程1)
#线程2 = MyThread的(2,线程2)
#与contextlib.nested(ThreadContainer(1,线程1),ThreadContainer(2,线程2))作为(T1,T2):
#t1.execute(print_time,5,1)
#t2.execute(print_time,5,2)
    T1 = MyThread的(1,线程1)
    T2 = MyThread的(2,线程2)
    与contextlib.nested(T1,T2):
        t1.execute(print_time,5,1)
        t2.execute(print_time,5,2)
    打印(退出主线程)


解决方案

这里的问题是,你想要的运行功能要等到执行函数被调用。

当然最明显的解决方法是调用执行你打电话之前启动

  t1.execute(print_time,5,1)
t2.execute(print_time,5,2)
与contextlib.nested(T1,T2):
    通过

...或者只是让执行通话启动,或传递函数的构造函数或启动呼叫,或者...

另外,你的设计意图是有点怪。线程函数是设计来处理,其中 _f 尚未确定的情况下......但希望等到 _f 已设置?


不过,这是可以想象的,这种问题可以想出一个更现实的设计,所以,让我们来看看如何解决这个问题。

首先,加入睡眠来解决一个问题线程几乎总是你正在做的事情非常错误的一个标志。这也是一个伟大的方式来引起其他可怕的性能问题(如:你的时间足够的地方让一切都是有效补充足够的睡眠 s时,需要30秒您的应用程序启动而不是30毫秒) - 和,差,竞争条件的错误(当然1秒总是有足够的时间,对吧?除非电脑捶打交换,或从休眠状态唤醒,或忙于使用所有其他程序CPU,或......)。

如果你想同步跨线程的操作,你需要使用同步对象。诀窍是知道正确的。阅读 锁定 >事件 (和3.x增加 屏障 ),并找到对一般线程教程得到一个什么样所有这些事情是更广泛的概念。*

在这种情况下,你已经得到了code,它在等待一些变化保存的状态,和其他code,它的进行更改,这是一对典型的用例的条件。所以:

 类MyThread的(threading.Thread):
    高清__init __(自我,主题ID,名称,条件):
        self.condition =条件
        # ... 和之前一样    DEF运行(个体经营):
        #...检查_f之前设置        与self.condition:
            虽然不self._f:
                self.condition.wait()
        self._f()        #......什么都想要

现在,您需要创建条件,把它传递给线程,通知吧。

您可以使用一个条件

 条件= threading.Condition()
T1 = MyThread的(1,线程1,状态)
T2 = MyThread的(2,线程2,条件)
与contextlib.nested(T1,T2):
    与条件:
        t1.execute(print_time,5,1)
        t2.execute(print_time,5,2)
        condition.notify_all()


另外,你可以为每个线程提供自己的条件

 类MyThread的(threading.Thread):
    高清__init __(自我,主题ID,姓名):
        self.condition =条件()
        # ... 和之前一样#...T1 = MyThread的(1,线程1)
T2 = MyThread的(2,线程2)
与contextlib.nested(T1,T2):
    与t1.condition:
        t1.execute(print_time,5,1)
        t1.condition.notify()
    与t2.condition:
        t2.execute(print_time,5,1)
        t2.condition.notify()


请注意,这不会让你明确的未设置 _f ,但它是pretty容易做到这一点。例如,您可以添加 _f_set 属性,并检查,而不是 _f ,所以有人可以叫执行(无)(然后通知)来唤醒你,让你没有 _f 的情况。


*警告:一些的命名是不一致的。有一个不同的东西也被称为壁垒,和不同的不同的事情也被称为篱笆,并有事件是由蟒蛇(其中有些是更像一个条件不同的pretty很多变种,但实际上并不是可用作这样),有时状态变量是由同步对象的保护,而不是在同步对象的实际共享状态,等等...

This question is a follow up from following question:With statement and python threading

I have been experimenting with python threading api. I have this code which works for what I want to achieve :---->function execution before invoking run on python thread.

However to do this, I invariably have to call time.sleep(1) in the run() method to make it proceed to execute().Otherwise the thread exits without function assignment and execution.Is there a better way to achieve this type of waiting?

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 ")

解决方案

The problem here is that you want the run function to wait until the execute function is called.

Of course the obvious solution is to call execute before you call start:

t1.execute(print_time,5,1)
t2.execute(print_time,5,2)
with contextlib.nested(t1, t2):
    pass

… or just make execute call start, or pass the function in to the constructor or the start call, or…

Also, your intended design is a bit weird. The thread function is designed to handle the case where _f hasn't been set… but you want it to wait until _f has been set?


But it's conceivable that this kind of problem could come up in a more realistic design, so, let's look at how to solve it.

First, adding sleep to solve a threading problem is almost always a sign that you're doing something very wrong. It's also a great way to cause either horrible performance problems (as in: by the time you add enough sleeps in enough places to make everything mostly work, it takes 30 seconds for your app to start instead of 30 milliseconds)—and, worse, race-condition bugs (surely 1 second is always enough time, right? unless the computer is thrashing swap, or waking up from hibernate, or busy with other programs using all the CPU, or…).

If you're trying to synchronize actions across threads, you need to use a synchronization object. The trick is knowing the right one. Read the docs for Lock through Event (and 3.x adds Barrier), and find a tutorial on threading in general to get a broader idea of what all of these things are for.*

In this case, you've got code that's waiting for some change to saved state, and other code that's making the change, which is the prototypical use case for a 'Condition'. So:

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

Now, you need to create the Condition, pass it to the threads, and notify it.

You could use a single 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()


Alternatively, you can give each thread its own 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()


Note that this doesn't allow you to explicit "not set" _f, but it's pretty easy to do that. For example, you can add an _f_set attribute, and check that instead of _f, so someone can call execute(None) (and then notify) to wake you up and get you to the "no _f" case.


* Warning: Some of the naming is inconsistent. There's a different thing also called "barrier", and a different different thing also called "fence", and there are many variants of "event" that are pretty different from Pythons (some of which are more like a condition, but aren't actually usable as such), and sometimes a "condition variable" is the actual shared state protected by the sync object rather than the sync object, and so on…

这篇关于随着句和线程:让运行前执行功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆