从Python访问Matlab时进行回避轮询 [英] Evade polling when accessing Matlab from Python

查看:131
本文介绍了从Python访问Matlab时进行回避轮询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从Python(在Windows上,通过COM接口远程访问)访问Matlab.我的目标是:Matlab正在做一些工作,并永久更改某个变量的值.我需要知道该值何时超过某个常数.现在,我正在不确定循环中轮询Matlab以获取该变量的值,该循环会在超出该值时中断.但是,我想让Matlab做这件事,并告诉 me 这是什么情况,而我懒洋洋地坐在那里听.有没有办法做到这一点,如何做到最好?我曾想过定义一个要传递给Matlab的回调函数,该函数在超出事件范围内会触发Python中非繁忙等待循环的中断,但我怀疑这样做是否可行.我对Matlab和Python都不太了解,所以很感谢线索.

I would like to access Matlab from Python (on Windows, remotely and via COM-interface). My goal is: Matlab is doing some work and permanently changes the value of a certain variable. I need to know when the value exceeds some constant. Right now, I'm polling Matlab for the value of that variable in an indefinite loop which breaks on exceeding the value. However, I would like to let Matlab do the work and tell me when that is the case, while I'm lazily sitting there listening. Is there a way to achieve this, and how is it done best? I have thought of defining a callback function I'm passing to Matlab, which on the exceed-event triggers a break out of a non-busy-wait-loop in Python, but I doubt it would work. I'm not very experienced neither in Matlab nor Python, so cues are much appreciated.

涉及很多其他代码,但是基本上现在就像

There's a lot of other code involved, but basically right now it is like

connectToMatlab(*args)
while True:
    val = getValueFromMatlab()
    if val > constant or timeout: break

我的想法是

def breakLoop():
    ...  

connectToMatlab(breakLoop, *args)
while True:
    time.sleep(1) # or some alternate non-busy-wait

,然后让Matlab在val > constant上调用breakLoop().但是,我不知道是否可以让Matlab进行回调,如果可以的话,如何实现这样的breakLoop() -Function.

and then let Matlab invoke breakLoop() upon val > constant. However, I don't know if it is possible to let Matlab do that with a callback and if yes, how to implement such a breakLoop()-Function.

推荐答案

您可以采用另一种方式,并使用文件系统作为在MATLAB和Python之间传递消息的方式.

You can go about this the other way, and use the file system as a way to pass the messages between MATLAB and Python.

在您的MATLAB代码中,每次更改变量时,请检查其是否超过某个阈值.如果是这样,请在预定位置创建一个新文件.认为这是触发事件.

Inside your MATLAB code, each time you change the variable, check if it exceed some threshold. If it does, create a new file in a predetermined location. Think of this as triggering an event.

现在在您的python代码中,使用一些可用的方法来更改在文件系统中,然后通过指示一些变量来打破循环来进行响应.

Now inside your python code, use some of the available ways to the listen to changes in the file system, and respond by indicating some variable to break the loop.

以下是提出的解决方案的框架:

Here is a skeleton of the solution proposed:

%# directory that Python code is watching for modifications
dirPath = 'some_directory';

x = 0;
for i=1:1000
    %# some lengthy operation
    pause(0.5)
    x = x + 1;

    %# check if variable exceeds threshold
    if x > 10
        %# save the workspace to MAT-file inside the directory watched.
        %# this shall trigger the notification in Python
        save( fullfile(dirPath,'out.mat') )
        break
    end
end

python_code.py

import os, sys, time
import win32file, win32event, win32con

# stub your functions in my case
def connectToMatlab():
  pass
def getValueFromMatlab():
  return 99

# path to predetermined directory to watch
dirPath = "some_directory"
dirPath = os.path.abspath(dirPath)

# start/connect to a MATLAB session, running the script above
connectToMatlab()

# set up folder watching (notify on file addition/deletion/renaming)
print "Started watching '%s' at %s" % (dirPath, time.asctime())
change_handle = win32file.FindFirstChangeNotification(
  dirPath, 0, win32con.FILE_NOTIFY_CHANGE_FILE_NAME)

# time-out in 10 sec (win32event.INFINITE to wait indefinitely)
timeout = 10000

try:
  # block/wait for notification
  result = win32event.WaitForSingleObject(change_handle, timeout)

  # returned because of a change notification
  if result == win32con.WAIT_OBJECT_0:
    # retrieve final result from MATLAB
    print "MALTAB variable has exceeded threshold at %s" % time.asctime()
    val = getValueFromMatlab()

  # timed out
  elif result == win32con.WAIT_TIMEOUT:
    print "timed-out after %s msec at %s" % (timeout,time.asctime())
    val = None    # maybe to indicate failure

finally:
  # cleanup properly
  win32file.FindCloseChangeNotification(change_handle)

# work with val
print val

WaitForSingleObject 函数以检查指定对象的状态.如果它没有信号,则调用线程将进入高效的等待状态,并在等待信号通知对象(或经过超时间隔)之前消耗很少的处理器时间.

The WaitForSingleObject function start by checking the state of the specified object. If it is nonsignaled, the calling thread enters an efficient wait state and consumes very little processor time while waiting until the object is signaled (or the time-out interval elapses).

您会看到当线程引用处于非信号状态的对象时,会立即进行上下文切换,即将其从处理器中取出并置于等待/睡眠模式.稍后,当对象发出信号时,线程将放回可运行队列并准备执行.

You see when the thread references the object which is in non-signaled state, there is an immediate context switch i.e. it is taken down from the processor and put into a wait/sleep mode. Later when the object is signaled, the thread is put back to the runnable queue and is ready for execution.

在这种等待中,尽管上下文切换会有一些开销,但在等待状态下不会浪费CPU周期.

In this kind of waiting there is no wastage of CPU cycles in wait state, although there is a some overhead in context switching.

将此与轮询并等待"方法进行比较,在该方法中,线程以某种循环的形式等待并检查目标对象的状态.这被称为旋转或繁忙等待,这可能会浪费CPU周期.

Compare this against the "poll-and-wait" approach, where the thread waits and checks for the state of the object of interest in some kind of a loop. This is known as spin or busy wait, which can prove to be a wastage of CPU cycles.

现在感谢pywin32模块,我们可以使用那些 WaitFor... 直接起作用.该实现应该是标准示例在MSDN中给出.

Now thanks to pywin32 module, we can use use those WaitFor... functions directly. The implementation should be a straightforward port of the standard example given in MSDN.

或者,您也可以将PyQt库及其 QFileSystemWatcher 类,而不是直接使用Win32 API.

Alternatively you can use the PyQt library with its QFileSystemWatcher class instead of directly using the Win32 API.

这篇关于从Python访问Matlab时进行回避轮询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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