2

PythonからMatlabにアクセスしたい(Windowsの場合、リモートで、COMインターフェイスを介して)。私の目標は次のとおりです。Matlabはいくつかの作業を行っており、特定の変数の値を永続的に変更します。値がある定数を超えるときを知る必要があります。現在、Matlabをポーリングして、値を超えると中断する無期限のループ内のその変数の値を調べています。ただし、Matlabに作業を任せて、その場合はいつか教えてもらいたいと思います。その間、私はゆっくりと座って聞いています。これを達成する方法はありますか、そしてそれはどのように最善に行われていますか?Matlabに渡すコールバック関数を定義することを考えました。これは、exceed-eventで、Pythonの非ビジーウェイトループからの脱却をトリガーしますが、機能するとは思えません。私はMatlabでもPythonでもあまり経験がないので、手がかりを高く評価しています。

他にもたくさんのコードが関係していますが、基本的には今は次のようになっています

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にを呼び出しbreakLoop()させますval > constant。ただし、Matlabにコールバックを使用してそれを実行させることが可能かどうか、可能である場合は、そのような関数を実装する方法がbreakLoop()わかりません。

4

1 に答える 1

2

これは別の方法で行うことができ、MATLABとPythonの間でメッセージを渡す方法としてファイルシステムを使用できます。

MATLABコード内で、変数を変更するたびに、変数がしきい値を超えているかどうかを確認します。含まれている場合は、所定の場所に新しいファイルを作成します。これをイベントのトリガーと考えてください。

Pythonコード内で、ファイルシステムの変更をリッスンするために利用可能ないくつかの方法を使用し、ループを中断するための変数を指定することで応答します。


編集

提案されたソリューションの骨組みは次のとおりです。

matlab_script.m

%# 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関数は、指定されたオブジェクトの状態をチェックすることから始まります。シグナルが送信されない場合、呼び出し元のスレッドは効率的な待機状態になり、オブジェクトがシグナルを送信されるまで(またはタイムアウト間隔が経過するまで)待機している間、プロセッサ時間をほとんど消費しません。

スレッドがシグナルなしの状態にあるオブジェクトを参照すると、すぐにコンテキストスイッチが発生します。つまり、プロセッサからダウンして待機/スリープモードになります。後でオブジェクトが通知されると、スレッドは実行可能キューに戻され、実行の準備が整います。

この種の待機では、コンテキストスイッチングにいくらかのオーバーヘッドがありますが、待機状態でのCPUサイクルの浪費はありません。

これを「ポーリングアンドウェイト」アプローチと比較してください。このアプローチでは、スレッドが待機し、ある種のループで対象のオブジェクトの状態をチェックします。これはスピンまたはビジーウェイトと呼ばれ、CPUサイクルの浪費であることが判明する可能性があります。

pywin32モジュールのおかげで、これらのWaitFor...関数を直接使用できるようになりました。実装は、MSDNで提供されている標準の例の単純な移植である必要があります。

または、Win32 APIを直接使用する代わりに、 QFileSystemWatcherクラスでPyQtライブラリを使用することもできます。

于 2012-06-09T20:03:25.060 に答える