始终使用 neg[.z.w] 来确保所有消息都是异步的?
Always use neg[.z.w] to ensure that all messages are asynchronous?
考虑服务器上的以下定义:
f:{show "Received ",string x; neg[.z.w] (`mycallback; x+1)}
在客户端:
q)mycallback:{show "Returned ",string x;}
q)neg[h] (`f; 42)
q)"Returned 43"
在 q for motrtals
中,提示说:
When performing asynchronous messaging, always use neg[.z.w] to ensure
that all messages are asynchronous. Otherwise you will get a deadlock
as each process waits for the other.
因此我将服务器上的定义更改为:
f:{show "Received ",string x; .z.w (`mycallback; x+1)}
一切顺利,我没有看到任何死锁。
谁能给我一个例子来说明为什么我应该总是使用 neg[.z.w]
?
如果我理解你的问题是正确的,我想你是在问同步和异步消息是如何工作的。您提供的示例的问题在于 x+1 是一个非常简单的查询,几乎可以立即进行评估。对于更具说明性的示例,请考虑将其更改为睡眠(或更费力的计算,例如大型数据库查询)。
在您的服务器端定义:
f:{show "Received ",string x;system "sleep 10"; neg[.z.w] (`mycallback; x+1)}
然后在您的客户端可以发送同步查询:
h(`f; 42)
多次。这样做你会看到客户端不再有 q 提示,因为它必须等待响应。这些请求可以排队,因此会在很长一段时间内阻塞客户端和服务器。
或者,如果您要调用:
(neg h)(`f; 42)
在客户端。您会看到 q 提示符仍然存在,因为客户端没有等待响应。这是一个异步调用。
现在,在您的服务器端函数中,您正在考虑使用 .z.w 或 neg .z.w。然而,从服务器的角度来看,这遵循完全相同的原则。如果对查询的响应足够大,则消息传递可能会花费大量时间。因此,通过使用 neg 可以异步发送此响应,因此在此过程中服务器不会被阻塞。
注意:如果您在 windows 机器上工作,您将需要将睡眠换成超时,或者如果您按照我的示例进行操作,则可能需要 while 循环。
更新:我想造成这种死锁的一种方法是有两个依赖进程,试图同步调用对方。例如:
q)\p 10002
q)h:hopen 10003
q)g:{h (`f1;`)}
q)h (`f;`)'
一侧
q)\p 10003
q)h:hopen 10002
q)f:{h (`g;`)}
q)f1:{show "test"}
另一方面。这将导致两个进程都被卡住,因此永远不会显示测试。
Joe 的回答几乎涵盖了所有内容,但对于您的具体示例,如果客户端调用
就会发生死锁
h (`f; 42)
客户端在处理下一个请求之前正在等待服务器的响应,但是服务器在完成客户端的请求之前也在等待客户端的响应。
考虑服务器上的以下定义:
f:{show "Received ",string x; neg[.z.w] (`mycallback; x+1)}
在客户端:
q)mycallback:{show "Returned ",string x;}
q)neg[h] (`f; 42)
q)"Returned 43"
在 q for motrtals
中,提示说:
When performing asynchronous messaging, always use neg[.z.w] to ensure that all messages are asynchronous. Otherwise you will get a deadlock as each process waits for the other.
因此我将服务器上的定义更改为:
f:{show "Received ",string x; .z.w (`mycallback; x+1)}
一切顺利,我没有看到任何死锁。
谁能给我一个例子来说明为什么我应该总是使用 neg[.z.w]
?
如果我理解你的问题是正确的,我想你是在问同步和异步消息是如何工作的。您提供的示例的问题在于 x+1 是一个非常简单的查询,几乎可以立即进行评估。对于更具说明性的示例,请考虑将其更改为睡眠(或更费力的计算,例如大型数据库查询)。
在您的服务器端定义:
f:{show "Received ",string x;system "sleep 10"; neg[.z.w] (`mycallback; x+1)}
然后在您的客户端可以发送同步查询:
h(`f; 42)
多次。这样做你会看到客户端不再有 q 提示,因为它必须等待响应。这些请求可以排队,因此会在很长一段时间内阻塞客户端和服务器。
或者,如果您要调用:
(neg h)(`f; 42)
在客户端。您会看到 q 提示符仍然存在,因为客户端没有等待响应。这是一个异步调用。
现在,在您的服务器端函数中,您正在考虑使用 .z.w 或 neg .z.w。然而,从服务器的角度来看,这遵循完全相同的原则。如果对查询的响应足够大,则消息传递可能会花费大量时间。因此,通过使用 neg 可以异步发送此响应,因此在此过程中服务器不会被阻塞。
注意:如果您在 windows 机器上工作,您将需要将睡眠换成超时,或者如果您按照我的示例进行操作,则可能需要 while 循环。
更新:我想造成这种死锁的一种方法是有两个依赖进程,试图同步调用对方。例如:
q)\p 10002
q)h:hopen 10003
q)g:{h (`f1;`)}
q)h (`f;`)'
一侧
q)\p 10003
q)h:hopen 10002
q)f:{h (`g;`)}
q)f1:{show "test"}
另一方面。这将导致两个进程都被卡住,因此永远不会显示测试。
Joe 的回答几乎涵盖了所有内容,但对于您的具体示例,如果客户端调用
就会发生死锁h (`f; 42)
客户端在处理下一个请求之前正在等待服务器的响应,但是服务器在完成客户端的请求之前也在等待客户端的响应。