我正试图使用ErlPort将Elixir与Python混合使用,因此我决定阅读一些关于它的教程以及有关所有相关内容的文档。我了解逻辑是如何工作的,以及每个功能是什么。但是,我在发布消息和接收Python响应时遇到问题
根据我所阅读的内容和我所做的工作,我了解到当我使用cast_count/1
强制转换消息时,这是由handle_cast/2
处理的,然后由Python函数handle_message()
处理,然后这个函数使用函数cast_message()
强制转换消息,并从erlport.erlang
导入一个cast()
。最后,Elixir应该使用handle_info/2
处理从Python接收的消息。我认为这个函数没有被执行,但我不知道原因,尽管我在不同的来源和GenServer和ErlPort的文档中调查了很多这方面的内容
在我的例子中,我有下一个结构:lib/python_helper.ex
使erport工作,并lib/server.ex
调用和转换Python函数
lib/python_helper.ex
defmodule WikiElixirTest.PythonHelper do
def start_instance do
path =
[:code.priv_dir(:wiki_elixir_test), "python"]
|> Path.join()
|> to_charlist()
{:ok, pid} = :python.start([{:python_path, path}])
pid
end
def call(pid, module, function, arguments \\ []) do
pid
|> :python.call(module, function, arguments)
end
def cast(pid, message) do
pid
|> :python.cast(message)
end
def stop_instance(pid) do
pid
|> :python.stop()
end
end
lib/server.ex
defmodule WikiElixirTest.Server do
use GenServer
alias WikiElixirTest.PythonHelper
def start_link() do
GenServer.start_link(__MODULE__, [])
end
def init(_args) do
session = PythonHelper.start_instance()
PythonHelper.call(session, :counter, :register_handler, [self()])
{:ok, session}
end
def cast_count(count) do
{:ok, pid} = start_link()
GenServer.cast(pid, {:count, count})
end
def call_count(count) do
{:ok, pid} = start_link()
GenServer.call(pid, {:count, count}, :infinity)
end
def handle_call({:count, count}, _from, session) do
result = PythonHelper.call(session, :counter, :counter, [count])
{:reply, result, session}
end
def handle_cast({:count, count}, session) do
PythonHelper.cast(session, count)
{:noreply, session}
end
def handle_info({:python, message}, session) do
IO.puts("Received message from Python: #{inspect(message)}")
{:stop, :normal, session}
end
def terminate(_reason, session) do
PythonHelper.stop_instance(session)
:ok
end
end
priv/python/counter.py
import time
import sys
from erlport.erlang import set_message_handler, cast
from erlport.erlterms import Atom
message_handler = None
def cast_message(pid, message):
cast(pid, (Atom('python', message)))
def register_handler(pid):
global message_handler
message_handler = pid
def handle_message(count):
try:
print('Received message from Elixir')
print(f'Count: {count}')
result = counter(count)
if message_handler:
cast_message(message_handler, result)
except Exception as e:
print(e)
pass
def counter(count=100):
i = 0
data = []
while i < count:
time.sleep(1)
data.append(i+1)
i = i + 1
return data
set_message_handler(handle_message)
注意:我删除了@doc
以照亮代码片段。是的,我知道目前没有使用sys
,Python中的catchException
{
如果我在iex
(iex -S mix
)中测试它,我会得到下一个:
iex(1)> WikiElixirTest.Server.cast_count(19)
Received message from Elixir
Count: 19
:ok
我想指出call_count/1
和handle_call/1
可以很好地工作:
iex(3)> WikiElixirTest.Server.call_count(10)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
当我发布消息时,Elixir与Python的通信是成功的,而Python与Elixir的通信不是成功的,我做错了什么
好吧,@Everett在问题中报告说我在^{中错误地关闭了原子
这必须是:
虽然这并不能解决问题,但它能帮助我找到解决方案。在修复了第一部分(
(Atom('python'), message)
)之后,当我执行cast_count/1
时,我从Python得到一条消息:虽然第一次它让我有点困惑,因为我在等待类似“从Python接收消息:预期的字节对象”之类的消息,但由于} 中发现了错误,它是
handle_info/2
。但是,我决定检查ErlPort的代码,并在the line 66 of ^{Atom
类的一部分。因此,错误出现在消息的第一部分atom中,因此我将其指定为二进制:然后我检查了一下:
而且效果很好!因此,即使考虑到我对消息元组的错误输入,这里的问题是
Atom()
需要一个二进制文件这种误解可能是因为我后面的第一个ErlPort tutorial使用了Python 2,在这个版本中
str
是一个字节字符串,而在Python 3中,需要将字符串转换为字节,因为str
是一个文本字符串相关问题 更多 >
编程相关推荐