C# 函数执行时异步等待
我有一个阻塞函数,它执行异步 MySQL 查询并在获得结果时返回结果。原因是异步的,因为该程序不允许在查询期间锁定。
当用户按下按钮时会调用该函数,因此在第一个查询完成之前该函数可能会被调用多次。我想我可以添加一个布尔值来检查查询是否正在执行,并让函数等到它完成后再继续,但它没有按预期工作。我使用的两个 DoEvents() 有一些问题。如果您注释掉其中任何一个,它都会运行得很好,只是 UI 会冻结。
如何使函数在执行查询时进行非阻塞等待,以及在获取查询本身时进行非阻塞等待?我真的更愿意将其保留在一个线程上,因为函数本身会阻塞调用它的代码。任何帮助将不胜感激!
public Exception LastError;
public MySqlConnection Conn;
public MySqlDataReader Reader;
public bool IsExecuting = false;
public MySqlDataReader MySQL_Query(string Query, [Optional] params string[] Values)
{
while (IsExecuting)
{
System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(20);
}
if (IsConnected() == false)
ConnectToDatabase();
for (int i = 0; i < Values.Length; i++)
Values[i] = MySQL_SafeValue(Values[i]);
if (Reader != null && Reader.IsClosed == false)
Reader.Close();
IsExecuting = true;
try
{
MySqlCommand Cmd = new MySqlCommand(String.Format(Query, Values), Conn);
IAsyncResult aRes = Cmd.BeginExecuteReader();
while (!aRes.IsCompleted)
{
System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(20);
}
Reader = Cmd.EndExecuteReader(aRes);
IsExecuting = false;
}
catch (Exception e)
{
IsExecuting = false;
LastError = e;
return null;
}
return Reader;
}
I have a blocking function that executes an asynchronous MySQL query and returns the result when it is obtained. The reason is is asynchronous is this program is not allowed to lock up during a query.
The function is called when the user presses a button, so the function may get called several times before the first query completes. I thought I could add a boolean to check whether or not a query is executing and have the function wait until it's done before continuing, but it is not working as intended. There is some issue with the two DoEvents() I use. If you comment out either one, it runs just fine, except the UI freezes.
How can I make the function do a non-blocking wait while a query is executing, as well as do a non-blocking wait while the query itself is being fetched? I would really prefer to keep this on one thread, as the function itself is blocking to the code that called it. Any help would b e greatly appreciated!
public Exception LastError;
public MySqlConnection Conn;
public MySqlDataReader Reader;
public bool IsExecuting = false;
public MySqlDataReader MySQL_Query(string Query, [Optional] params string[] Values)
{
while (IsExecuting)
{
System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(20);
}
if (IsConnected() == false)
ConnectToDatabase();
for (int i = 0; i < Values.Length; i++)
Values[i] = MySQL_SafeValue(Values[i]);
if (Reader != null && Reader.IsClosed == false)
Reader.Close();
IsExecuting = true;
try
{
MySqlCommand Cmd = new MySqlCommand(String.Format(Query, Values), Conn);
IAsyncResult aRes = Cmd.BeginExecuteReader();
while (!aRes.IsCompleted)
{
System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(20);
}
Reader = Cmd.EndExecuteReader(aRes);
IsExecuting = false;
}
catch (Exception e)
{
IsExecuting = false;
LastError = e;
return null;
}
return Reader;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您不应使用
DoEvents
和Sleep
来创建响应式 UI。有关在 UI 中执行异步操作的信息,请参阅 BackgroundWorker 类。You should not be using
DoEvents
andSleep
to create a responsive UI. For performing asynchronous operations in the UI, see the BackgroundWorker class.执行异步工作的方法有很多种,从直接使用线程池到像BackgroundWorker 这样的助手。
然而,这并没有回答你的主要问题,这有点矛盾,即你想要进行非阻塞等待。我建议您根本不要阻止,也就是说,如果您已经在执行,则忽略该请求并且什么都不做。在这种情况下,您可能需要提供一些反馈来表示“已经在工作”。
现在来看看您的代码的实际问题。正如 Adam 所指出的,您确实不应该使用 DoEvents 和 Sleep。相反,您将长时间运行的工作项发布到某个后台任务,并使用标志在 UI 线程和运行任务的线程之间进行同步,例如
There are numerous ways to do async work, from using the thread pool directly to helpers like BackgroundWorker.
However this does not answer your primary question which is a little contradictory, i.e. you want to do a non-blocking wait. I would suggest that you not block at all which is to say, if you are already executing then ignore the request and do nothing. You may want to give some feedback to say "already working" in this situation.
Now to actual issues with your code. As Adam has noted you really shouldn't be using DoEvents and Sleep. Instead you post the long running work item to some background task and use a flag to synchronise between the UI thread and the thread running your task, e.g.
尽管当您提出问题时这不是一个选项,但如果您可以升级到 .NET 4.5,那么现在就有一种更简洁的方法来进行异步操作,同时本质上仍以与同步代码相同的方式编写。这涉及使用新的
async
和await
关键字。请参阅:
异步入门,了解新功能的介绍特点
这里是一个专门引用 MySQL 连接的问题。
Though it wasn't an option when you asked your question, if you can upgrade to .NET 4.5 there is now a much cleaner way to to asynchronous operations while still essentially writing in the same fashion you would for synchronous code. This involves using the new
async
andawait
keywords.See:
An Async Primer for an intro to the new features
And here is a SO question specifically referencing MySQL connections.