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


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

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

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

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


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實例化。

  為什么RequestHandler中post或者get請求被認為是一個后台的線程方法?這個問題從使用tornado的代碼中可以窺得一二。代碼如下:

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 兩個統計到的數據差別很大,請根據實際情況來選擇。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM