编辑:
像@MattP一样,我会添加我的理解声明:
背景
我认为你正在运行一个名为abaqus的产品。abaqus产品包括一个链接的python解释器,你可以以某种方式访问它(可能是通过在命令行上运行abaqus python foo.py
)。
您还有一个单独的python安装,在同一台机器上。您正在开发代码,可能包括numpy / scipy,以在该python安装中运行。
这两个安装是不同的:它们具有不同的二进制解释器,不同的库,不同的安装路径等。但是它们位于同一物理主机上。
您的目标是使由您编写的“纯Python”程序与在“Abaqus Python”环境中运行的一个或多个脚本进行通信,以便这些脚本可以在Abaqus系统内执行工作并返回结果。
解决方案
这里是基于套接字的解决方案。有两个部分:abqlistener.py
和abqclient.py
。这种方法的优点是使用了一个明确定义的“等待工作”的机制。没有文件轮询等。而且它是一个“硬”API。您可以从同一台机器上运行相同版本的python的进程,或者从不同的机器上连接到侦听器进程,或者从不同版本的python,ruby或C或perl甚至COBOL中连接到它。它允许您在系统中放置真正的“气隙”,因此您可以以最小的耦合开发两个部分。
服务器部分是abqlistener
。意图是您将会把这些代码复制到您的Abaqus脚本中。然后,abq进程将成为一个服务器,在特定端口号上监听连接,并响应工作。发送回复,或不发送。等等。
我不确定您是否需要为每个作业做设置工作。如果是这样,那将成为连接的一部分。这只是启动ABQ,在一个端口上监听(永远),并处理请求。任何特定于作业的设置都必须是工作过程的一部分。 (也许发送参数字符串或配置文件的名称或其他内容。)
客户端部分是abqclient
。这可以移到模块中,也可以只是复制/粘贴到您现有的非ABQ程序代码中。基本上,您打开与正确的主机:端口组合的连接,然后您正在与服务器交谈。发送一些数据,获取一些数据,等等。
这些东西主要是从在线示例代码中抓取的。因此,如果您开始挖掘任何内容,它应该看起来很熟悉。
这里是abqlistener.py:
usage = """
abacus python abqlistener.py [--host 127.0.0.1 | --host mypc.example.com ] \\
[ --port 2525 ]
Sets up a socket listener on the host interface specified (default: all
interfaces), on the given port number (default: 2525). When a connection
is made to the socket, begins processing data.
"""
import argparse
parser = argparse.ArgumentParser(description='Abacus listener',
add_help=True,
usage=usage)
parser.add_argument('-H', '--host', metavar='INTERFACE', default='',
help='Interface IP address or name, or (default: empty string)')
parser.add_argument('-P', '--port', metavar='PORTNUM', type=int, default=2525,
help='port number of listener (default: 2525)')
args = parser.parse_args()
import SocketServer
import json
class AbqRequestHandler(SocketServer.BaseRequestHandler):
"""Request handler for our socket server.
This class is instantiated whenever a new connection is made, and
must override `handle(self)` in order to handle communicating with
the client.
"""
def do_work(self, data):
"Do some work here. Call abaqus, whatever."
print "DO_WORK: Doing work with data!"
print data
return { 'desc': 'low-precision natural constants','pi': 3, 'e': 3 }
def handle(self):
self.data = self.request.recv(1024).strip()
print "SERVER: {} wrote:".format(self.client_address[0])
print self.data
result = self.do_work(self.data)
self.response = json.dumps(result)
print "SERVER: response to {}:".format(self.client_address[0])
print self.response
self.request.sendall(self.response)
if __name__ == '__main__':
print args
server = SocketServer.TCPServer((args.host, args.port), AbqRequestHandler)
print "Server starting. Press Ctrl+C to interrupt..."
server.serve_forever()
以下是abqclient.py
的代码:
usage = """
python2.7 abqclient.py [--host HOST] [--port PORT]
Connect to abqlistener on HOST:PORT, send a message, wait for reply.
"""
import argparse
parser = argparse.ArgumentParser(description='Abacus listener',
add_help=True,
usage=usage)
parser.add_argument('-H', '--host', metavar='INTERFACE', default='',
help='Interface IP address or name, or (default: empty string)')
parser.add_argument('-P', '--port', metavar='PORTNUM', type=int, default=2525,
help='port number of listener (default: 2525)')
args = parser.parse_args()
import json
import socket
message = "I get all the best code from stackoverflow!"
print "CLIENT: Creating socket..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "CLIENT: Connecting to {}:{}.".format(args.host, args.port)
s.connect((args.host, args.port))
print "CLIENT: Sending message:", message
s.send(message)
print "CLIENT: Waiting for reply..."
data = s.recv(1024)
print "CLIENT: Got response:"
print json.loads(data)
print "CLIENT: Closing socket..."
s.close()
当我将它们一起运行时,下面是它们打印的内容:
$ python2.7 abqlistener.py --port 3434 &
[2] 44088
$ Namespace(host='', port=3434)
Server starting. Press Ctrl+C to interrupt...
$ python2.7 abqclient.py --port 3434
CLIENT: Creating socket...
CLIENT: Connecting to :3434.
CLIENT: Sending message: I get all the best code from stackoverflow!
CLIENT: Waiting for reply...
SERVER: 127.0.0.1 wrote:
I get all the best code from stackoverflow!
DO_WORK: Doing work with data!
I get all the best code from stackoverflow!
SERVER: response to 127.0.0.1:
{"pi": 3, "e": 3, "desc": "low-precision natural constants"}
CLIENT: Got response:
{u'pi': 3, u'e': 3, u'desc': u'low-precision natural constants'}
CLIENT: Closing socket...
参考资料:
argparse
,SocketServer
,json
,socket
都是“标准” Python 库。
Python 3.x
环境,并调用例如"abaqus python aq_script.py"
,该脚本读取并将abaqus
数据进行封装。然后再使用另一个输出脚本返回到abaqus
,以相同的方式进行封装。虽然速度较慢,但如果需要scipy
或tensorflow
等库,它仍然比在abaqus的古老numpy
实现中实现要快。 - Daniel Fsubprocess.call('abaqus cae script = test.py',shell=True)
。这会输出一条消息,表示abaqus许可证服务器已启动,并且打开了给定脚本的abaqus程序。我需要一种方法从我的主脚本与该脚本进行通信。像之前提到的那样反过来构建并不合逻辑。 - mooisjkennumpy
确实是同时运行两个独立程序的好处之一。我想知道你的解决方案是否与我的当前解决方法相符?还有,我该如何让Abaqus在接收信号时更加高效,而不是不断地检查一个已经被pickled的文件是否发生了变化? - mooisjken