Vb.net 并行共享资源。ForEach
如何在Parallel.ForEach循环中控制对共享资源的访问?我正在尝试并行下载多个文件,我希望捕获有关下载失败的信息,以便用户稍后可以重新尝试下载。但是,我担心如果多个下载同时失败,应用程序将抛出异常,因为一个线程将在另一个线程写入文件时尝试访问该文件 在下面的代码中,我想知道如何在RepeaterRequestPath控制对文件的访问。RequestSet是一个字符串列表,表示我试图下载的资源的IDVb.net 并行共享资源。ForEach,vb.net,io,parallel.foreach,Vb.net,Io,Parallel.foreach,如何在Parallel.ForEach循环中控制对共享资源的访问?我正在尝试并行下载多个文件,我希望捕获有关下载失败的信息,以便用户稍后可以重新尝试下载。但是,我担心如果多个下载同时失败,应用程序将抛出异常,因为一个线程将在另一个线程写入文件时尝试访问该文件 在下面的代码中,我想知道如何在RepeaterRequestPath控制对文件的访问。RequestSet是一个字符串列表,表示我试图下载的资源的ID Dim DownloadCnt As Integer = 0 Dim ParallelO
Dim DownloadCnt As Integer = 0
Dim ParallelOpts As New ParallelOptions()
ParallelOpts.MaxDegreeOfParallelism = 4
Parallel.ForEach(RequestSets, ParallelOpts, Sub(RequestSet)
Try
DownloadCnt += 1
Dim XmlUrl As String = String.Format("{0}{1}{2}", "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=", String.Join(",", RequestSet), "&retmode=xml&rettype=abstract")
DownloadFile(XmlUrl, String.Format("{0}\TempXML{1}.xml", XMLCacheDir, DownloadCnt))
Catch ex As WebException
Using Response As WebResponse = ex.Response
Dim statCode As Integer = CInt(DirectCast(Response, HttpWebResponse).StatusCode)
MessageBox.Show(String.Format("Failed to retrieve XML due to HTTP error {0}. Please hit the 'Retrieve XML' button to re-run retrieval after the current set is complete.", statCode))
If Not File.Exists(RepeatRequestPath) Then
File.WriteAllLines(RepeatRequestPath, RequestSet)
Else
File.AppendAllLines(RepeatRequestPath, RequestSet)
End If
End Using
End Try
End Sub)
您需要使用信号量来控制对共享资源的访问。您一次只需要一个线程访问错误文件,因此初始化信号量,使其只允许1个线程进入。调用_pool.WaitOne应该捕获信号量,然后在完成创建/写入文件后释放信号量
Private Shared _pool As Semaphore
_pool = = New Semaphore(0, 1)
Dim DownloadCnt As Integer = 0
Dim ParallelOpts As New ParallelOptions()
ParallelOpts.MaxDegreeOfParallelism = 4
Parallel.ForEach(RequestSets, ParallelOpts, Sub(RequestSet)
Try
DownloadCnt += 1
Dim XmlUrl As String = String.Format("{0}{1}{2}", "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=", String.Join(",", RequestSet), "&retmode=xml&rettype=abstract")
DownloadFile(XmlUrl, String.Format("{0}\TempXML{1}.xml", XMLCacheDir, DownloadCnt))
Catch ex As WebException
Using Response As WebResponse = ex.Response
Dim statCode As Integer = CInt(DirectCast(Response, HttpWebResponse).StatusCode)
MessageBox.Show(String.Format("Failed to retrieve XML due to HTTP error {0}. Please hit the 'Retrieve XML' button to re-run retrieval after the current set is complete.", statCode))
_pool.WaitOne()
Try
If Not File.Exists(RepeatRequestPath) Then
File.WriteAllLines(RepeatRequestPath, RequestSet)
Else
File.AppendAllLines(RepeatRequestPath, RequestSet)
End If
Catch ex as Exception
'Do some error handling here.
Finally
_pool.Release()
End Try
End Using
End Try
End Sub)
您需要使用信号量来控制对共享资源的访问。您一次只需要一个线程访问错误文件,因此初始化信号量,使其只允许1个线程进入。调用_pool.WaitOne应该捕获信号量,然后在完成创建/写入文件后释放信号量
Private Shared _pool As Semaphore
_pool = = New Semaphore(0, 1)
Dim DownloadCnt As Integer = 0
Dim ParallelOpts As New ParallelOptions()
ParallelOpts.MaxDegreeOfParallelism = 4
Parallel.ForEach(RequestSets, ParallelOpts, Sub(RequestSet)
Try
DownloadCnt += 1
Dim XmlUrl As String = String.Format("{0}{1}{2}", "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=", String.Join(",", RequestSet), "&retmode=xml&rettype=abstract")
DownloadFile(XmlUrl, String.Format("{0}\TempXML{1}.xml", XMLCacheDir, DownloadCnt))
Catch ex As WebException
Using Response As WebResponse = ex.Response
Dim statCode As Integer = CInt(DirectCast(Response, HttpWebResponse).StatusCode)
MessageBox.Show(String.Format("Failed to retrieve XML due to HTTP error {0}. Please hit the 'Retrieve XML' button to re-run retrieval after the current set is complete.", statCode))
_pool.WaitOne()
Try
If Not File.Exists(RepeatRequestPath) Then
File.WriteAllLines(RepeatRequestPath, RequestSet)
Else
File.AppendAllLines(RepeatRequestPath, RequestSet)
End If
Catch ex as Exception
'Do some error handling here.
Finally
_pool.Release()
End Try
End Using
End Try
End Sub)
在VB.NET中保护共享资源的常用方法是使用 因此,您应该在
Parallel.ForEach()循环之前创建一个锁对象:
Dim lock = New Object
然后在循环中使用它:
SyncLock lock
File.AppendAllLines(RepeatRequestPath, RequestSet)
End SyncLock
还要注意,即使文件还不存在,也可以使用AppendAllLines()
,因此不必检查该文件。在VB.NET中保护共享资源的常用方法是使用
因此,您应该在Parallel.ForEach()循环之前创建一个锁对象:
Dim lock = New Object
然后在循环中使用它:
SyncLock lock
File.AppendAllLines(RepeatRequestPath, RequestSet)
End SyncLock
还要注意的是,即使文件还不存在,您也可以使用AppendAllLines()
,因此您不必检查它。svick的解决方案几乎是正确的。但是,如果需要保护对共享变量的访问,还需要在类级别将锁对象声明为共享
这是正确的:
Friend Class SomeClass
Private Shared _lock As New Object
Private Shared sharedInt As Integer = 0
Sub Main()
SyncLock _lock
sharedInt += 1
End SyncLock
End Sub
End Class
如果使用非共享锁对象,synclock将仅保护变量不受同一实例内多个访问线程的影响,而不会跨实例访问 斯维克的解决方案几乎是正确的。但是,如果需要保护对共享变量的访问,还需要在类级别将锁对象声明为共享
这是正确的:
Friend Class SomeClass
Private Shared _lock As New Object
Private Shared sharedInt As Integer = 0
Sub Main()
SyncLock _lock
sharedInt += 1
End SyncLock
End Sub
End Class
如果使用非共享锁对象,synclock将仅保护变量不受同一实例内多个访问线程的影响,而不会跨实例访问 良好的点释放不会被称为。不确定try-catch块在catch块中的可接受程度。我选择使用svick的解决方案,因为它较短,但我感谢您的帮助!良好的点释放不会被称为。不确定try-catch块在catch块中的可接受程度。我选择使用svick的解决方案,因为它较短,但我感谢您的帮助!完美的不过,这是一个简单的问题。我可以在Try-Catch块的Try部分的不同文件上使用相同的锁吗?或者我必须实例化一个单独的对象吗?调用DownloadFile后,我想对另一个文件执行相同的操作。@user667118您可以。另一个问题是你是否应该这样做,因为这意味着如果一个线程想写入一个文件,它必须等待另一个线程写入另一个文件。我认为这不会有太大问题,因为写入文件不需要很长时间。总的来说,我仍然节省了很多时间,因为这段代码以前是以同步方式运行的。太棒了!不过,这是一个简单的问题。我可以在Try-Catch块的Try部分的不同文件上使用相同的锁吗?或者我必须实例化一个单独的对象吗?调用DownloadFile后,我想对另一个文件执行相同的操作。@user667118您可以。另一个问题是你是否应该这样做,因为这意味着如果一个线程想写入一个文件,它必须等待另一个线程写入另一个文件。我认为这不会有太大问题,因为写入文件不需要很长时间。总的来说,我仍然节省了很多时间,因为这段代码以前是以同步方式运行的。