Web服务:一次只允许一个线程执行

时间:2012-07-23 10:09:31

标签: .net multithreading web-services ftpwebrequest

商业案例:

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

问题:

  1. 我的解决方案是否正确?
  2. 如果是,如何只允许一个线程在Web服务中执行?请注意,我只想在下载时这样做。上传应该在并行线程中工作..
  3. 有更好的解决方案吗?
  4. 我使用的是.NET 4.0。

3 个答案:

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