简体   繁体   English

如何防止WebClient冻结程序

[英]How to prevent webclient from freezing program

Currently I am using a webclient to download several XML files from a site. 目前,我正在使用Web客户端从站点下载多个XML文件。 But for the duration of the download unity freezes up till these downloads finishes. 但是在下载期间,统一冻结直到这些下载完成。 Which take roughly 30 seconds, most of this time be taken up by the waitforsecond() call that the internal compiler makes, causing a 12*2 1 second wait calls. 这大约需要30秒,大部分时间都由内部编译器进行的waitforsecond()调用占用,从而导致12 * 2 1秒的等待调用。

Is there a way to bypass this/ run this on another thread but still being able to call it from unity? 有没有办法绕过这个/在另一个线程上运行,但仍然可以统一调用它?

 // 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;
            }
        }
    }

Instead of using a blocking method like DownloadFile you should use an asynchronous method like DownloadFileTaskAsync and the async/await keywords to ensure processing continues after the method returns data: 不要使用类似DownloadFile的阻塞方法,而应使用类似DownloadFileTaskAsyncasync/await关键字的异步方法,以确保该方法返回数据后继续处理:

 // 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;
        }
    }
}

This will convert PreObtainData to an asynchronous method as well. 这也会将PreObtainData转换为异步方法。 You should modify its caller to handle tasks as well. 您还应该修改其调用方以处理任务。 If this method is called inside an event handler, this can be done by changing the handler's signature to async void instead of void eg: 如果在事件处理程序中调用此方法,则可以通过将处理程序的签名更改为async void而不是void来完成此操作,例如:

private async voidForm1_Load(object sender, System.EventArgs e)
{
    ...
    await PreObtainData(...);
    ...
}

Microsoft exposes a BackgroundWorker class in the System.ComponentModel namespace that is designed for precisely these kinds of operations. Microsoft在System.ComponentModel命名空间中公开了BackgroundWorker类,该类专门用于此类操作。 All you do is add a background worker to your form and capture the DoWork and RunWorkerCompleted events associated with it. 您要做的只是将一个背景工作人员添加到窗体中,并捕获与其关联的DoWork和RunWorkerCompleted事件。 You'll perform your downloads in the DoWork event and then perform any completion work and/or cleanup in the RunWorkerCompleted event. 您将在DoWork事件中执行下载,然后在RunWorkerCompleted事件中执行任何完成工作和/或清理。

As @Panagiotis indicated, I'm not sure your question has as much to do with Unity as it does with running a background process to prevent the main thread from locking up. 正如@Panagiotis指出的那样,我不确定您的问题与Unity的关系是否与运行后台进程以防止主线程锁定有关。 Try out the BackgroundWorker and see if it accomplishes your goal. 试用BackgroundWorker,看看它是否可以实现您的目标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM