商业案例:
我有ASMX web service
从某个远程目录复制/删除/下载文件。我的WebMethod
创建了一个执行所有这些操作的业务类实例。在下载的情况下,我检查哪个文件是最新的文件并下载。下载后,我想立即删除它。但是,在多线程场景中,我尝试删除的文件很可能已被其他一些线程删除。
我的解决方案:
为避免此类问题,我希望Web服务一次只执行一个线程。对WebMethod
的任何其他调用应该等到上一个线程完成下载和删除操作。
为此我在业务类中声明了一个static
变量。在业务类的业务方法(从WebMethod
调用)开始时,我在此静态对象上调用lock
。因此,在未释放该静态变量(对象)上的lock
之前,其他Web服务调用将不会执行业务方法中的代码。
public class FileOperator
{
private static object locker = new object();
public void DownloadAndDeleteFile(string fileName)
{
lock(locker)
{
// All business logic goes here.
}
}
}
WebMethod
中的代码如下所示。
FileOperator fileOperator = new FileOperator();
fileOperator.DownloadAndDeleteFile("File1.txt");
问题:
我使用的是.NET 4.0。
答案 0 :(得分:2)
以下是我对您的要求的理解:
多个客户端/线程正在执行Web方法,该方法从远程服务器下载文件,下载后从远程服务器删除下载的文件。
现在各个线程可以使用相同或不同的文件进行下载。
当前实现的问题是,因为你在函数级别有通用Mutex(锁),所以即使一个线程想要下载一个文件,而这个文件没有被任何其他线程访问,它也必须等待另一个线程正在处理另一个文件,这会在扩展系统时达到性能大的时间,因为它将同步所有客户端,无论需求如何。
我正在考虑根据要在远程服务器上访问的文件/资源,锁定可能存在的线路上的可能解决方案。请考虑以下几点:
在服务器方法上维护一个静态对象列表,其中每个对象被分配给不同的文件/资源,您可以维护一个字典,该字典将创建的静态对象映射到文件。当一个线程带有文件名时,它会获取相关对象,如果它已经存在,否则会创建一个新对象。现在,它尝试获取该对象的锁定,如果它是第一个线程,它将获得访问权限,否则它必须等待,如果另一个线程正在处理同一个对象。 在函数内部,您可以先检查文件是否存在,然后再继续前进或快速退出互斥锁。
将会有一个对所有线程都有效的通用锁,持续时间很短,只维护所有线程的字典对象的sanctitiy。所以,每个线程都可以检查文件是否存在
//粗略实施(你需要消毒)
公共类FileOperator { private static object locker = new object();
private static List<object> fileObjects;
private static Dictionary fileObjectsDictionary;
public void DownloadAndDeleteFile(string fileName)
{
lock(locker)
{
if(fileObjects == null)
fileObjects = new List<object>();
if(fileObjectsDictionary == null)
fileObjectsDictionary = new Dictionary();
// check whether list contains fileName
// For First time Add file to a given index
// Create an Object using same index and add to the dictionary
// For any other time get the index and fetch the object from dictionary
}
lock(Dictionary Object)
{
// All business logic
}
}
}
//这样所有线程都不会在同一点等待
希望这有帮助,
Mrinal
答案 1 :(得分:1)
如果您的网络服务是单一入口点,那么您实际上根本不必担心这一点。为什么?因为即使您可以异步调用Web服务,Web服务也会默认以同步方式执行请求:Is ASMX WebService or WCF or aspx pages are async by default?
答案 2 :(得分:0)
为什么不尝试删除原子?
lock(obj)
if(IO.File.Exists(someFilePath))
try
{
IO.File.Delete(someFilePath));
}catch(IOException){//do nothing}