0

商业案例:

我有一个ASMX web service从某个远程目录复制/删除/下载文件。MyWebMethod创建了一个执行所有这些操作的业务类的实例。在下载的情况下,我检查哪个文件是最新的并下载它。下载后,我想立即删除它。但是,在多线程场景中,我尝试删除的文件很可能已被其他线程删除。

我的解决方案:

为避免此类问题,我希望 Web 服务一次只执行一个线程。对 的任何其他调用都WebMethod应该等到前一个线程完成下载和删除操作。

为此,我static在我的商务舱中声明了一个变量。WebMethod在业务类中我的业务方法(从 调用)开始时,我lock在这个静态对象上调用 。因此,其他 Web 服务调用将不会执行业务方法中的代码,直到该lock静态变量(对象)未被释放。

 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");

问题:

  1. 我的解决方案正确吗?
  2. 如果是,如何只允许从 Web 服务中执行一个线程?请注意,我只想为下载执行此操作。上传应该在并行线程中工作。
  3. 有更好的解决方案吗?

我正在使用 .NET 4.0。

4

3 回答 3

2

以下是我对您的要求的理解:

  • 多个客户端/线程正在执行一个 Web 方法,该方法正在从远程服务器下载文件,下载后从远程服务器删除下载的文件。

  • 现在各种线程,可能会去相同或不同的文件,下载。

  • 当前实现的问题是,由于您在函数级别具有通用互斥锁(锁),因此即使一个线程想要下载一个未被任何其他线程访问的文件,它也必须等待另一个线程正在工作在不同的文件上,这将在您扩展系统时大大影响性能,因为它会同步所有客户端,而不管要求如何。

我只是在考虑基于要在远程服务器上访问的文件/资源​​的锁定可能存在的行的可能解决方案。考虑以下几行:

  • 在服务器方法上维护静态对象列表,其中每个对象被分配给不同的文件/资源​​,您可以维护一个字典,它将创建的静态对象映射到文件。当一个线程带有文件名时,它会获取相关对象,如果它已经存在,否则会创建一个新对象。现在,它尝试获取该对象上的锁,如果它是第一个线程,它将获得访问权限,否则它必须等待,如果另一个线程正在处理同一个对象。在函数内部,您可以先检查文件是否存在,然后再继续前进或快速退出互斥锁。

  • 将有一个对所有线程都有效的通用锁,在很短的时间内只为所有线程维护字典对象的神圣性。所以,每个线程都可以检查文件的存在

// 粗略的实现(你需要清理)

公共类 FileOperator { 私有静态对象储物柜 = 新对象();

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

}

// 这样所有线程就不会在同一点等待

希望这可以帮助,

米纳尔

于 2012-07-27T06:41:12.223 回答
1

如果您的 Web 服务是单一入口点,那么您实际上根本不必担心这一点。为什么?因为即使您可以异步调用您的 Web 服务,Web 服务也会默认以同步方式执行请求:ASMX WebService 或 WCF 或 aspx 页面是否默认是异步的?

于 2012-07-23T11:40:00.210 回答
0

你为什么不尝试原子删除?

lock(obj)
    if(IO.File.Exists(someFilePath))
       try
       {
           IO.File.Delete(someFilePath));
        }catch(IOException){//do nothing}
于 2012-07-23T10:20:06.297 回答