如何防止webclient冻结程序
How to prevent webclient from freezing program
目前我正在使用网络客户端从站点下载几个 XML 文件。但是在下载期间,unity 会冻结,直到这些下载完成。这大约需要 30 秒,大部分时间被内部编译器调用的 waitforsecond() 占用,导致 12*2 1 秒等待调用。
有没有办法在另一个线程上绕过这个/ 运行 这个但仍然能够从统一中调用它?
// the form is a login form
public void PreObtainData(ref MonavisaRequestForm request, string dateAndTime, string fileDateAndTime)
{
if (!initialized)
Initialize();
try
{
if (!request.webclient.IsBusy && requestQueue.Count == 0)
{
request.url = request.url.Replace("&", "%26");
request.url = request.url.Replace("+", "%2B");
Uri uri = new Uri(string.Format("http://localhost/login.php?username={0}&password={1}&request={2}", request.username, request.password, request.url));
request.webclient.DownloadFile(uri, @"Nioo Graph Data " + fileDateAndTime + ".xml");
}
else if (!request.webclient.IsBusy && requestQueue.Count > 0)
{
Uri uri = new Uri(string.Format("http://localhost/login.php?username={0}&password={1}&request={2}", requestQueue.Peek().username, requestQueue.Peek().password, requestQueue.Peek().url));
requestQueue.Peek().webclient.DownloadFile(uri, @"Nioo Graph Data " + fileDateAndTime + ".xml");
requestQueue.Dequeue();
}
else
{
requestQueue.Enqueue(request);
}
}
catch (System.Net.WebException ex)
{
if (ex.Status != System.Net.WebExceptionStatus.ProtocolError)
{
throw;
}
}
}
Microsoft 在 System.ComponentModel 命名空间中公开了一个 BackgroundWorker class,它正是为这些类型的操作而设计的。您所做的就是向您的表单添加一个后台工作者,并捕获与其关联的 DoWork 和 RunWorkerCompleted 事件。您将在 DoWork 事件中执行下载,然后在 RunWorkerCompleted 事件中执行任何完成工作 and/or 清理。
正如@Panagiotis 所指出的,我不确定您的问题与 Unity 的关系是否与 运行 防止主线程锁定的后台进程有关。试用 BackgroundWorker,看看它是否能实现您的目标。
而不是使用像 DownloadFile
这样的阻塞方法,你应该使用像 DownloadFileTaskAsync 这样的异步方法和 async/await
关键字来确保在方法 returns 数据之后继续处理:
// the form is a login form
public async Task PreObtainData(ref MonavisaRequestForm request, string dateAndTime, string fileDateAndTime)
{
if (!initialized)
Initialize();
try
{
if (!request.webclient.IsBusy && requestQueue.Count == 0)
{
...
await request.webclient.DownloadFileTaskAsync(uri, @"Nioo Graph Data " + fileDateAndTime + ".xml");
}
else if (!request.webclient.IsBusy && requestQueue.Count > 0)
{
...
await requestQueue.Peek().webclient.DownloadFileTaskAsync(uri, @"Nioo Graph Data " + fileDateAndTime + ".xml");
requestQueue.Dequeue();
}
else
{
requestQueue.Enqueue(request);
}
}
catch (System.Net.WebException ex)
{
if (ex.Status != System.Net.WebExceptionStatus.ProtocolError)
{
throw;
}
}
}
这也会将 PreObtainData
转换为异步方法。您还应该修改其调用者以处理任务。如果在事件处理程序中调用此方法,可以通过将处理程序的签名更改为 async void
而不是 void
来完成,例如:
private async voidForm1_Load(object sender, System.EventArgs e)
{
...
await PreObtainData(...);
...
}
目前我正在使用网络客户端从站点下载几个 XML 文件。但是在下载期间,unity 会冻结,直到这些下载完成。这大约需要 30 秒,大部分时间被内部编译器调用的 waitforsecond() 占用,导致 12*2 1 秒等待调用。
有没有办法在另一个线程上绕过这个/ 运行 这个但仍然能够从统一中调用它?
// the form is a login form
public void PreObtainData(ref MonavisaRequestForm request, string dateAndTime, string fileDateAndTime)
{
if (!initialized)
Initialize();
try
{
if (!request.webclient.IsBusy && requestQueue.Count == 0)
{
request.url = request.url.Replace("&", "%26");
request.url = request.url.Replace("+", "%2B");
Uri uri = new Uri(string.Format("http://localhost/login.php?username={0}&password={1}&request={2}", request.username, request.password, request.url));
request.webclient.DownloadFile(uri, @"Nioo Graph Data " + fileDateAndTime + ".xml");
}
else if (!request.webclient.IsBusy && requestQueue.Count > 0)
{
Uri uri = new Uri(string.Format("http://localhost/login.php?username={0}&password={1}&request={2}", requestQueue.Peek().username, requestQueue.Peek().password, requestQueue.Peek().url));
requestQueue.Peek().webclient.DownloadFile(uri, @"Nioo Graph Data " + fileDateAndTime + ".xml");
requestQueue.Dequeue();
}
else
{
requestQueue.Enqueue(request);
}
}
catch (System.Net.WebException ex)
{
if (ex.Status != System.Net.WebExceptionStatus.ProtocolError)
{
throw;
}
}
}
Microsoft 在 System.ComponentModel 命名空间中公开了一个 BackgroundWorker class,它正是为这些类型的操作而设计的。您所做的就是向您的表单添加一个后台工作者,并捕获与其关联的 DoWork 和 RunWorkerCompleted 事件。您将在 DoWork 事件中执行下载,然后在 RunWorkerCompleted 事件中执行任何完成工作 and/or 清理。
正如@Panagiotis 所指出的,我不确定您的问题与 Unity 的关系是否与 运行 防止主线程锁定的后台进程有关。试用 BackgroundWorker,看看它是否能实现您的目标。
而不是使用像 DownloadFile
这样的阻塞方法,你应该使用像 DownloadFileTaskAsync 这样的异步方法和 async/await
关键字来确保在方法 returns 数据之后继续处理:
// the form is a login form
public async Task PreObtainData(ref MonavisaRequestForm request, string dateAndTime, string fileDateAndTime)
{
if (!initialized)
Initialize();
try
{
if (!request.webclient.IsBusy && requestQueue.Count == 0)
{
...
await request.webclient.DownloadFileTaskAsync(uri, @"Nioo Graph Data " + fileDateAndTime + ".xml");
}
else if (!request.webclient.IsBusy && requestQueue.Count > 0)
{
...
await requestQueue.Peek().webclient.DownloadFileTaskAsync(uri, @"Nioo Graph Data " + fileDateAndTime + ".xml");
requestQueue.Dequeue();
}
else
{
requestQueue.Enqueue(request);
}
}
catch (System.Net.WebException ex)
{
if (ex.Status != System.Net.WebExceptionStatus.ProtocolError)
{
throw;
}
}
}
这也会将 PreObtainData
转换为异步方法。您还应该修改其调用者以处理任务。如果在事件处理程序中调用此方法,可以通过将处理程序的签名更改为 async void
而不是 void
来完成,例如:
private async voidForm1_Load(object sender, System.EventArgs e)
{
...
await PreObtainData(...);
...
}