Long delay with WWW.isDone

We’re seeing a multi-second hiccup in our application, and according to the profiler it appears to be during WWW.isDone. First, a bit of background:

Our application is a data viz tool. When it launches, we do a bunch of setup and also launch a search for the latest data to our ‘core’, which is a RESTful API on a server. When the search returns, we do a bunch of things (parse the JSON, instantiate some NGUI objects, kick off additional downloads, etc.). During this time, we’re seeing a huge pause, but only in the webplayer. The standalone app has no pause at all - it runs smoothly.

After a bit of testing, it appears that a large chunk of the delay is being caused by our download manager checking to see if the download is complete by calling dl.isDone(). Here’s what I’m seeing in the profiler:

[10165-www+bug+profiler.jpg|10165]

As you can see, each isDone call appears to be taking 50 ms, with UnityCrossDomainHelper.GetSecurityPolicy being the only thing listed under isDone. Here’s the relevant code from our download manager:

private IEnumerator monitorDownload()
{
    while (state == State.Downloading)
    {
        if (www.isDone)
        {

MonitorDownload basically just runs on a loop, yielding every frame, and checks up on the download as it’s happening, along with managing download state (something we introduced in our download manager), etc.

So, in summary, for some reason calling www.isDone in some cases is causing up to a 50 ms delay, but only in the webplayer.

The webplayer uses the browsers HTTP pipeline for any request (to benefit from the browser caching, cookie and session handling), so if you ask WWW about ‘isDone’ it will have to call out to the browser, get and process the response and feed it back into the scripting layer for you to consume during the next frame / fixed udpate.

This normally shouldn’t cause any delays and alike and hasn’t basing on my experience, but my implementations always ensured to limit the amount of parallel downloads to a handfull at max. many browsers have limits for parallel http connections, if you fire up 40 in a single round, you are risking to lock yourself down for a lengthy amount of time

The easy and non-performance kiling way is removing the isDone loop and use yield return www but this only works if the download progress is irrelevant.

If you need to access the download progress, you could use a longer yield timeframe as the progress will not jump from 0 to 100% in 0.016 / 0.02s, So using something like yield return new WaitForSeconds(0.1f) or even 0.5f would make a major difference.

This appears to be a bug internal to Unity, something to do with UnityCrossDomainHelper.GetSecurityPolicy. It doesn’t appear to have anything to do with the number of downloads, and is reproducible with a skeleton project.

Submitted bug 538108:

Large delay with WWW.isDone

I’m consistently seeing a 50 ms delay per call to WWW.isDone, when the following the application is running as a webplayer app (even in the editor when target is set to webplayer)

This 50 ms delay is only seen when WWW.isDone in turn calls UnityCrossDomainHelper.GetSecurityPolicy, which it does not appear to do for every download, and doesn’t appear to do every frame for the downloads it does affect.

I’ve included a repro project with a test scene and script to start 7 downloads and then launch a coroutine for each to call WWW.isDone once per frame. I’ve included 2 profiler screenshots showing frame 1 and frame 2 of running the application in the editor. As you can see, in frame 1 there are 7 downloads, and 2 calls are made to GetSecurityPolicy, resulting in around 100 ms of delay. In the very next frame, the 7 downloads are still active and no calls are made to GetSecurityPolicy, with a result of 0.00 ms of delay for the same code.

In our main application, I have seen the total delay get as high as 1100 ms in rare instances when we’re running a couple dozen downloads simultaneously. This only happens for the webplayer - the standalone app is unaffected. The delay seems perfectly linear - each call to GetSecurityPolicy adds 50 ms of delay. I’ve seen this happen for as few as 3 calls to WWW.isDone in a single frame and as many as 30.