python 方法沒法在線程中使用(附python獲取網絡流量)

  在python中,定義一個方法,直接調用能夠,可是建立一個線程來調用就可能致使失敗。這種現象多出如今使用com對象進行系統操做時,並且是以線程的形式調用。python

  異常提示以下:syntax error。WMI returned a syntax error: you're probably running inside a thread without first calling pythoncom.CoInitialize[Ex] (no underlying exception)web

  仔細觀察的話,異常提示中已經給出瞭解決方案。在運行一個線程的時候須要調用pythoncom.CoInitialize()方法。鄙人在程序中使用了WMI模塊,試圖獲取部分系統信息。json

  異常的緣由(推測)是com的機制問題。因爲COM機制容許任意兩組件之間相互通訊而沒必要關心是在何種計算機上的何種操做系統下運行,也不用關心組件是使用何種語言編制的,這使COM技術擁有了強大的生命力。初始化COM環境的目的是使調用COM的API工做正常,也就是在COM操做以前調用CoInitialize或CoInitializeEX因此在線程函數中,若是使用com對象就必須調用CoInitialize或CoInitializeEX ,同時在退出時使用CoUninitialize來釋放對象。
  案例:app


c = wmi.WMI() interfaces = c.Win32_PerfRawData_Tcpip_NetworkInterface() print len(interfaces) rec = send = 0.0 for t in interfaces: print t.Name rec += float(t.BytesReceivedPersec) / 1024 / 1024 send += float(t.BytesSentPersec) / 1024 / 1024 print rec, send

 

  這段代碼是根據電腦的網卡獲取上下行的流量(即發送流量和接收流量),直接運行是能夠的。可是在tornado的RequestHandler的get或者post方法中使用時,會拋出異常syntax error及相關提示。在RequestHandler中,post或者get請求被認爲是一個後臺的線程方法,因此須要在實例化WMI這個com組件以前先進行com實例化。tcp

  爲何RequestHandler中post或者get請求被認爲是一個後臺的線程方法?這個問題從使用tornado的代碼中能夠窺得一二。代碼以下:ide

if __name__ == '__main__':
    app = tornado.web.Application(
        handlers=[(r"/test/(\w+)", testHandler),
                  (r'/', MainHandler)]
    )
    server = tornado.httpserver.HTTPServer(app)
    server = server.listen(8848)
    tornado.ioloop.IOLoop.instance().start();

  在給tornado配置了路由規則以後,咱們開啓了httpserver的服務,最後建立進程來使tornado運行起來。而每次的post或者get請求則是經過路由調用相應的Handler,這些都是在線程中執行的。故案例中經過com組件WMI來獲取系統流量放在get方法中就會報錯。修改後以下:函數

    def get(self):
        res = {}
        pythoncom.CoInitialize()
        c = wmi.WMI()
        interfaces = c.Win32_PerfRawData_Tcpip_NetworkInterface()
        print len(interfaces)
        rec = send = 0.0
        for t in interfaces:
            print t.Name
            rec += float(t.BytesReceivedPersec) / 1024 / 1024
            send += float(t.BytesSentPersec) / 1024 / 1024
        print rec, send
        res["receive"] = "%.2f" % rec
        res["send"] = "%.2f" % send       
        self._write_json(res)

  關於WMI模塊的使用能夠參考以下:http://wutils.com/wmi/root/cimv2/win32_perfrawdata_tcpip_networkinterface/   模塊中頗有不少類型(類型也有不少屬性),在具體使用的過程當中查詢起來很痛苦。案例中的統計流量用的是Win32_PerfRawData_Tcpip_NetworkInterface ,也有解決方案用的是Win32_PerfRawData_Tcpip_TCPv4 兩個統計到的數據差異很大,請根據實際狀況來選擇。tornado

  關於com機制的資料參考自:http://blog.csdn.net/chenglingsu6/article/details/5999134oop

相關文章
相關標籤/搜索