【发布时间】:2020-06-10 02:24:08
【问题描述】:
我已经阅读了很多关于“等待”任务的帖子......我似乎无法弄清楚这一点,因为这可能是实际等待任务的一个转折点,我正在等待一个对象要更新,如果没有超时。
我正在使用 redis,它在单独的消息处理程序中从 redis 服务器接收到基本 acks/nack 列表时正确更新它们。 (发布的代码太多,与这个问题无关)。
有问题的代码是如何调用下面的“WaitForAck”方法,它的职责是检查上面的列表是否附加了它正在等待的 ack/nack。
因此,如果列表 'dic_DEAL_OUTPUTRESP_MessageQueue' 被单独的 redis 处理程序附加,我希望能够在任何它将等待(7 秒)的地方调用 'WaitForAck',基本上阻止用户前进但不阻止任何其他线程,例如等待其更新的 redis 消息处理程序线程。
如果这应该是任何一种等待任务,我想我有点困惑,因为我不希望它是异步的?我希望用户等待 7 秒以查看它是否收到 ack/nack(列表有值),否则它会继续通知用户超时(单独处理)。
这是我的“WaitForAck”方法:
public static void WaitForAck(string origUuid)
{
DateTime dt = DateTime.Now;
Cursor.Current = Cursors.WaitCursor;
try
{
while (dic_DEAL_OUTPUTRESP_MessageQueue[origUuid] == null)
{
Debug.WriteLine("Waiting for Redis Ack");
Task.Delay(1000);
TimeSpan ts = DateTime.Now - dt;
if (ts.TotalSeconds > iWAIT)
{
break;
}
}
}
catch { }
Cursor.Current = Cursors.Default;
}
提前谢谢你
编辑:添加调用
private async void btnEnter_Click(object sender, EventArgs e)
{
// Process trade entry / amendment
if (ConfirmEntries() != 0)
{
this.DialogResult = DialogResult.None;
return;
}
DefineDeal();
// Attempt Commit
DEAL_REQ dEAL_REQ_ADD = new DEAL_REQ();
dEAL_REQ_ADD.msgTimestamp = ReturnUTCTime(DateTime.Now).ToString(sDATETIME_FORMATMS);
dEAL_REQ_ADD.uuid = Guid.NewGuid().ToString();
dEAL_REQ_ADD.commandKey = sMeFunction == sADD ? sDEAL_REQ_ADD : sDEAL_REQ_UPDATE;
dEAL_REQ_ADD.listenChannel = sRPC_CHANNEL_OUTPUT;
dEAL_REQ_ADD.payload = _fxTempDeal;
// Build json msg
string sJson = JsonConvert.SerializeObject(dEAL_REQ_ADD);
// Publish request
// Prime response queue with guid in key
dic_DEAL_OUTPUTRESP_MessageQueue.Add(dEAL_REQ_ADD.uuid, null);
//Task.Delay(100);
IDatabase db = redisConn.GetDatabase(redisDB);
db.ListLeftPush(sRPC_CHANNEL_INPUT, sJson);
//Task.Delay(100);
//string s = db.ListLeftPop(sRPC_LB_INPUT);
// Wait for ack
var value = await this.WaitForAck2(dEAL_REQ_ADD.uuid);
// Received ack/nack
if (value != null)
{
DEAL_RESP rESP = dic_DEAL_OUTPUTRESP_MessageQueue[dEAL_REQ_ADD.uuid];
if (rESP.commandKey == sDEAL_REQ_ADD_ACK || rESP.commandKey == sDEAL_REQ_UPDATE_ACK)
{
this.DialogResult = DialogResult.OK;
}
else if (rESP.commandKey == sDEAL_REQ_ADD_NACK || rESP.commandKey == sDEAL_REQ_UPDATE_NACK)
{
MessageBox.Show("Unable to " + sMeFunction + " this deal. Please contact support. Reason : " + rESP.payload.display_msg, sAPP_NAME, MessageBoxButtons.OK, MessageBoxIcon.Error);
this.DialogResult = DialogResult.Abort;
}
}
// Timed out
else
{
MessageBox.Show("Unable to " + sMeFunction + " this deal. Please contact support. Reason : Request Timeout", sAPP_NAME, MessageBoxButtons.OK, MessageBoxIcon.Error);
dic_DEAL_OUTPUTRESP_MessageQueue.Remove(dEAL_REQ_ADD.uuid);
dic_DEAL_TimedOut_MessageQueue.Add(dEAL_REQ_ADD.uuid, null);
this.DialogResult = DialogResult.Cancel;
}
}
public async Task<DEAL_RESP> WaitForAck2(string origUuid)
{
Stopwatch timer = new Stopwatch();
timer.Start();
while (timer.ElapsedMilliseconds < (7 * 1000))
{
if (await this.sync.WaitAsync(TimeSpan.FromSeconds(7)))
{
try
{
if (dic_DEAL_OUTPUTRESP_MessageQueue.TryGetValue(origUuid, out var value))
{
return value;
}
}
finally
{
this.sync.Release();
}
}
await Task.Delay(1000);
}
return null;
}
【问题讨论】:
-
不能给更新的方法引入回调?
-
我会查看 .net 中的线程原语 - 例如
ManualResetEvent -
据我了解:您的实际问题是您有一个可锁定的资源。您想针对该资源启动一个进程(必须遵守锁),即使它可能已被锁定。如果它被锁定,该进程应该能够等待(正常的锁定行为),但如果获取锁定它需要很长时间(不是正常的锁定行为)也会超时?
-
异常处理是我最讨厌的事情,这太可怕了。你吞下了所有的例外。这是在一条可怕的线路中处理异常的两个主要罪过。正如它所写的那样,那里甚至不应该有 be 一个 try 块。我收到了两篇我经常链接的关于异常处理的文章。他们应该帮助避免你做这样的代码:blogs.msdn.microsoft.com/ericlippert/2008/09/10/… | codeproject.com/Articles/9538/…
-
@itsme86 我不相信我可以做回调?因为它只是一个完全解耦的发布/订阅设置,即:一个进程请求更新到服务器,服务器发布一个 ack/nack 这个方法等待它......但它可能永远不会到来
标签: c# .net asynchronous