WriteFile buffers in memory

T

Tim Greenfield

Hi, I have a problem I'm hoping is not too unusual. I'm trying to push a
large file (50MB) out to the client from an ASP page. The reason I'm using
an ASP page is so I can start the reading at a particular offset. This ASP
page needs to be scaleable as it needs to support thousands of requests per
hour. I've found 2 solutions so far but both have their problems:
1) Using Response.WriteFile(filename, offset, length). This seems like the
perfect solution except that it puts the entire contents of the file in
memory per request... ouch! Anyone know of a way to put the file in some
global cache so it don't fill up my RAM per session? I could afford filling
up RAM per file as there are only a handful of files that will be
downloaded.
2) Writing the file 1K at a time to the output buffer w/ buffering disabled.
This works great; each request barely takes up any memory or CPU. However,
it seems to tie up 1 precious ASP thread per request. And it turns out that
ASP threads are very precious... they only give you 25 per processor by
default. Within a minute I'm out of threads and users get a "Server To Busy"
error. I can work around this by adding:
<httpRuntime appRequestQueueLimit="50000" /> to web.config
But all it does is make the 26th user wait for someone to finish their
download before granting access instead of giving them an error. Anyone know
how to increase the size and if so, am I treading on thin ice by increasing
it to some huge number like 1000?

Another solution I've been pursuing is to try to take the best of both
worlds. If I could create a module that uses the 1K at a time technique to
avoid memory hogging but get it return immediately by using multi-threading,
I think I could solve my problem. Unfortunately, I haven't been able to get
it to work yet.
' from my .aspx file:
Dim SendFile as New SendFile
SendFile.Response = Response
SendFile.Filename = Filename
SendFile.Offset = Offset
Dim t as New Threading.Thread(AddressOf SendFile.Go)
t.Start()

Can anyone offer any wisdom? I can't imagine I'm the first one to need to do
this. Thanks!

-- Tim
 
B

bruce barker

you are stuck tying up a couple threads per request. you can bump up the i/o
and workpool thread count. asp.net sets a max i/o thread count to 100 per
cpu.

what you are dealing with

1) iis keeps a thread pool to manage i/o connections to clients
2) iis run an isapi filter that handles asp.net pages
3) the asp.net filter keeps a pool of thread to manage i/o between it and
asp.net. the filter uses named pipes to talk to the asp.net worker process.
4) the asp.net worker process keeps a pool of threads to talk to the asp.net
filter over the named pipe connection
5) the asp.net worker process keeps a pool of threads to actually process a
request.

so with a file download, you will tieup:

1) an asp.net thread (until the last i/o flush)
2) an asp.net i/o thread (until flushed to the filter)
3) an asp.net i/o filter thread (until flushed to iis)
4) an iis i/o thread. (until i/o keep alive is canceled/times out)

if you need high performance, you should look at writing your own isapi
filter.

-- bruce (sqlwork.com)
 
T

Tim Greenfield

Thanks for the threading info. A max of 100 threads per CPU still seems
really low... 101 users all hitting a web page that takes a long time but
uses very few resources doesn't seem all that out of the ordinary. Oh well.

How do you suppose Response.WriteFile returns immediately? If I could get my
own code to behave like .WriteFile (but not tying up memory) then I could
have the best of both worlds. Maybe?
 
B

bruce barker

Response.Writefile flushes the output to the filter, releasing the asp.net
threads, but ties up the iis threads. asp.net will not scale up if the
transactions run much more than 2-3 seconds.

-- bruce (sqlwork.com)
 
T

Tim Greenfield

I just tried some stress testing on this method and it works perfectly! I
don't know why anyone would use .WriteFile(filename) anymore. It is however
lacking the offset & length params so I can send off just a portion of the
file. Any idea if MS will provide overloads for this function someday to
support the offset, length params? Or maybe there are already some and I'm
just unaware with how to use them? I tried Response.TransferFile(filename,
offset, length) but it didn't like that.

Thanks for the help,

-- Tim
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top