Python 3.6对象/类线程

时间:2017-01-17 18:21:43

标签: python python-3.x python-multithreading

我正在寻找使用Python 3创建一个“自包含的线程类”。

在高层次上,我希望我能做的是从我的“main”类中生成50个异步设备对象,然后根据需要使用它们的方法。当处理同步情况下的对象时,这并不困难,但随着我们转向异步处理,它会很快变得混乱。保持线程自包含在设备类中的主要思想是使我的基本(main.py)代码保持简化/清洁,并且没有任何线程管理。

在这种情况下我没有计划任何资源共享,所以我认为我没有任何线程锁定问题。

以下是一些示例代码,我希望有人可以提供一些提示或示例,使其成为一个自线程类(这意味着我不想在main.py级别管理线程):

示例main.py

from deviceworker import Device

availableworkers = {'USA':'services.groupkt.com', 'IND':'services.groupkt.com'}
Activeworkers = []

for name, ip in availableworkers.items():
    Activeworkers.append(Device(name, ip))

for worker in Activeworkers:
    worker.checkcountry()   # asynchronous call - (we don't want to wait for a response)
                            # The idea is to keep this code as clean as possible.

示例对象:deviceworker.py

import urllib.request
import urllib.parse
import json

class Device:
    def __init__(self, name, endpoint, preamble = 'state', port = 80 ):

        self.name = name
        self.connected =False
        self.connection = HTTPConnection(endpoint, preamble, port)
        self.getStatus()

    def getStatus(self, check_for = None):
        self.urlresponse = json.loads(self.connection.GET('get/USA/all')) #Use USA just to verify connection
        if check_for:
            pass

        self.connected = True

    def checkcountry(self):
        print(self.connection.GET('get/%s/all' % self.name))

class HTTPConnection:
    def __init__(self, endpoint, preamble = None, port = 80):

        if preamble: # specificing a version after the port and before method
            self.url = 'http://%s:%s/%s/' % (endpoint, port, preamble)
        else:
            self.url = 'http://%s:%s/' % (endpoint, port)
        print('_init_ url=%s' % self.url)

    def GET(self, operation):
        #try:
            #print('%s%s' % (self.url, operation))
        with urllib.request.urlopen('%s%s' % (self.url, operation)) as f:
             return f.read().decode('utf-8')
        #except Exception as e:
            #raise Exception("GET Request Failed")

为简单起见,我剥离了大部分异常处理。上面的示例应该有效。

---更新---

所以我觉得我有点想通了。仍然没有得到我期望从文档中获得的parrellism。

import threading
import urllib.request
import urllib.parse
import json
import time


class Device(threading.Thread):
    def __init__(self, name, endpoint, preamble = 'state', port = 80 ):
        threading.Thread.__init__(self)
        self.name = name
        self.connected = False
        self.connection = HTTPConnection(endpoint, preamble, port)
        print('%s: __init__' % self.name)

    def run(self):
        self.getStatus()
        print('%s: hit run()' % self.name)

    def getStatus(self):
        self.urlresponse = json.loads(self.connection.GET('get/USA/all')) #Use USA just to verify connection
        self.connected = True

    def checkcountry(self):
        if (self.name == 'USA'): self.waittime = 10
        else: self.waittime = 0

        print('%s: Getting Codes - wait time: %s' % (self.name, self.waittime))

        start_time=time.time()
        time.sleep(self.waittime)
        result =self.connection.GET('get/%s/all' % self.name)
        elapsed_time=time.time() - start_time
        print('%s: Got Codes - second: %s' % (self.name, elapsed_time))


class HTTPConnection:
    def __init__(self, endpoint, preamble = None, port = 80):
        if preamble: # specificing a version after the port and before method
            self.url = 'http://%s:%s/%s/' % (endpoint, port, preamble)
        else:
            self.url = 'http://%s:%s/' % (endpoint, port)

    def GET(self, operation):
        with urllib.request.urlopen('%s%s' % (self.url, operation)) as f:
             return f.read().decode('utf-8')


DeviceList = {'USA':'services.groupkt.com', 'IND':'services.groupkt.com'}
ActiveDevices = []

DeviceList = {'USA':'services.groupkt.com', 'IND':'services.groupkt.com'}
ActiveDevices = []

for name, ip in DeviceList.items():
    print('main: creating object for: %s' % name)
    newDevice = Device(name, ip)
    ActiveDevices.append(newDevice)
    newDevice.start()

for device in ActiveDevices:
    print('main: calling checkcountry() for: %s' % device.name)
    device.checkcountry()

结果如下:

main: creating object for: USA
USA: __init__
main: creating object for: IND
IND: __init__
main: calling checkcountry() for: USA
USA: Getting Codes - wait time: 10
USA: Got Codes - second: 10.167016744613647
main: calling checkcountry() for: IND
IND: Getting Codes - wait time: 0
IND: Got Codes - second: 0.11001110076904297

我将延迟添加到美国搜索中我会期望IND首先完成但看起来它已经序列化了。

我正在运行:

Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 07:18:10) [MSC v.1900 32 bit (Intel)] on win32

1 个答案:

答案 0 :(得分:0)

这是一个带有锁定的自定义线程示例,对我来说效果很好,比使用事件更好。

在 Colab 中试用。

import threading,time

i=0

luk=threading.Lock()


global i
global y
global t_num

class special_thread(threading.Thread):
    """This function starts a Thread class"""
    def __init__(self, execute,threadID , name,  daemon,args=(), repetitive=False,kwargs=None, interval_sec=60 ):
        threading.Thread.__init__(self)
        self.daemon = daemon
        self.stopped = threading.Event()
        self.interval_sec = interval_sec
        self.execute = execute
        self.name = name
        if kwargs is None:
            kwargs = {}
        self.args = args
        self.kwargs=kwargs
        self.repetitive=repetitive
        self.threadID = threadID
        print(args)
    def stop(self):
        self.stopped.set()
        self.join()

    def run(self):
        if self.repetitive:
            while not self.stopped.wait(self.interval_sec):
                self.execute(*self.args,**self.kwargs)
        else:
            self.execute(*self.args,**self.kwargs)


def center(t_num):
    y=0
    
    luk.acquire()
    caller = inspect.getouterframes(inspect.currentframe())[1][3]
    print(' {} is aquiring by {} '.format( caller,  str(time.ctime())))
    y+=t_num
    
    print( "Inside %s()" % caller)
    print('thread number is ',t_num,y)
    time.sleep(2*t_num)
    luk.release()
    print(' {} is releasing  by {} '.format( caller,  str(time.ctime())))

def target_uno():
  t_num=1
  center(t_num)

def target_dos():
  t_num=2
  center(t_num)


target_uno=special_thread(execute=target_uno, args=(),repetitive=True, interval_sec=1,threadID=10004,
                                                  name='target_uno',
                                                  daemon=False )

target_dos=special_thread(execute=target_dos, args=(),repetitive=True, interval_sec=1,threadID=10004,
                                                  name='target_dos',
                                                  daemon=False )

if __name__ == "__main__":

  target_uno.start()
  target_dos.start()
  time.sleep(20)
  target_uno.stop()
  target_dos.stop()