Web服务中文件下载的多线程并发问题
我有一个 asmx Web 服务,用于将文件下载到客户端。我的下载方法如下所示:
[WebMethod]
public byte[] DownloadFile(int id)
{
lock (this)
{
if (id == 0)
{
throw new ArgumentException("Input value is not valid");
}
IGWFileRepository fileRepository = new GWFileRepository();
GWFile file = fileRepository.GetFileById(id);
string path = Server.MapPath(RepositoryDir + "/" + file.DiscName);
BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read));
reader.BaseStream.Position = 0;
byte[] content = reader.ReadBytes(Convert.ToInt32(reader.BaseStream.Length));
reader.Close();
return content;
}
}
我的问题是,当我强调 100 个并发用户下载时,我得到一个异常:(
Exception: System.Web.Services.Protocols.SoapException: System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.IO.IOException: The process cannot access the file 'C:\Subversion\Repository\cb0a27e2-2d23-43b1-a12e-f07fb401cfc9.jpg' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at System.IO.File.Open(String path, FileMode mode, FileAccess access)
at GrenWebRepository.RepositoryService.DownloadFile(Int32 id) in C:\Subversion\Repository\RepositoryService.asmx.cs:line 62
--- End of inner exception stack trace ---
at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
at RepositoryTester.RS.RepositoryService.DownloadFile(Int32 id) in C:\Subversion\Repository\Web References\RS\Reference.cs:line 174
at RepositoryTester.User.DownloadAction() in C:\Subversion\Repository\RepositoryTester\RepositoryTester\User.cs:line 110
文件名模糊)
任何人都知道如何解决这个并发问题,是我的锁不正确吗?
I have a asmx web service that is used to download files to clients. My method for downloading is shown below:
[WebMethod]
public byte[] DownloadFile(int id)
{
lock (this)
{
if (id == 0)
{
throw new ArgumentException("Input value is not valid");
}
IGWFileRepository fileRepository = new GWFileRepository();
GWFile file = fileRepository.GetFileById(id);
string path = Server.MapPath(RepositoryDir + "/" + file.DiscName);
BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read));
reader.BaseStream.Position = 0;
byte[] content = reader.ReadBytes(Convert.ToInt32(reader.BaseStream.Length));
reader.Close();
return content;
}
}
My problem is that when i stress it with 100 simultaneous users downloading i get an exception:
Exception: System.Web.Services.Protocols.SoapException: System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.IO.IOException: The process cannot access the file 'C:\Subversion\Repository\cb0a27e2-2d23-43b1-a12e-f07fb401cfc9.jpg' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at System.IO.File.Open(String path, FileMode mode, FileAccess access)
at GrenWebRepository.RepositoryService.DownloadFile(Int32 id) in C:\Subversion\Repository\RepositoryService.asmx.cs:line 62
--- End of inner exception stack trace ---
at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
at RepositoryTester.RS.RepositoryService.DownloadFile(Int32 id) in C:\Subversion\Repository\Web References\RS\Reference.cs:line 174
at RepositoryTester.User.DownloadAction() in C:\Subversion\Repository\RepositoryTester\RepositoryTester\User.cs:line 110
(file names obscured)
Any one know how to solve this concurrency problem, is my lock not proper?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
快速而肮脏地,使用静态私有对象作为锁:
您当前的锁仅存在于所创建的类的实例上。为每个请求创建该类的新实例。我的解决方案存在以下问题:所有文件都将按顺序读取。如果这会导致性能问题,我只会考虑不同的方法。如果您想要并发访问不同的文件,您最终需要锁定文件名。这可能需要更多的工作。
Quick and dirty, use a static private object to use as a lock:
Your current lock only exists on the instance of the class that was created. New instances of the class are created for every request. My solution has the issue that all files will be read sequentially. I would only look at a different method if this causes performance problems. You will ultimately need to lock on the file name, if you want concurrent access to different files. That may take a bit more work.
我猜想在使用 FileStream 之后处理它会有所帮助。
尝试将其包含在 using 块中,如下所示:
I would guess disposing the FileStream after using it would help.
Try including it in a using block like so:
以下内容将简化您的代码,并且如果问题是由于未处理
FileStream
引起的,则可能会解决该问题:File.ReadAllBytes
使用FileAccess.Read 打开文件
和FileShare.Read
。The following will simplify your code, and might solve the problem if it was caused by not disposing of the
FileStream
:File.ReadAllBytes
opens the file withFileAccess.Read
andFileShare.Read
.