共享托管环境中的 Thread.Join
我想知道是否有人可以帮助我 - 我已经编写 VB.Net 很长时间了,但很少需要在 ASP.Net 中进行大量线程处理。
我正在尝试使用内存浏览器拍摄网站的“屏幕截图”。然后,这些图像会记录在数据库中并写入本地文件系统。
当我在本地服务器上运行它时,一切正常。当我在共享托管环境中运行它时,一切都很好,直到我执行 thread.join ,此时目标线程立即终止或卡住(没有从任何线程接收到进一步的日志记录信息)。我已在下面附加了日志,
还附加了关键代码,但简而言之,它是这样的:
对于每个 url,启动一个新线程并 thread.join 到它。新线程将加载浏览器并开始导航。然后它将进行空操作,直到浏览器加载完成,然后返回生成的位图图像(下一步)。
浏览器加载完成时,会触发一个事件。该处理程序从浏览器捕获位图图像并将其写入本地。
我已经做了一些谷歌搜索,但找不到很多相关信息 - 我发现了常见的共享托管问题,并确保我已经解决了它们(例如允许部分信任的调用者、签名程序集等...)
我如果任何对此主题有了解的人愿意为我指明正确的方向,我将不胜感激。
非常感谢
注意:我知道目前它会非常慢,因为它是按顺序处理图像的 - 但在我可以让它在一个线程上工作之前,我没有机会让它在多个线程上工作。
这很大程度上是由代码示例混合在一起的,我什至还没有开始整理/更好地组织它,所以对稍微混乱的代码表示歉意。
Public Function GetWebsiteImage(ByVal URL As String, Optional ByVal BrowserWidth As Integer = 1280, Optional ByVal BrowserHeight As Integer = 1024) As Bitmap
LogIt(String.Format("Webshot {1}: {0}", "Getting Image", id))
_URL = URL
_BrowserHeight = BrowserHeight
_BrowserWidth = BrowserWidth
Dim T As Thread
T = New Thread(New ThreadStart(AddressOf GenerateImage))
T.SetApartmentState(ApartmentState.STA)
'T.IsBackground = True
LogIt(String.Format("Webshot {1}: {0}", "Starting Thread", id))
T.Start()
'*** THIS IS THE LAST LOG ENTRY I SEE ***
LogIt(String.Format("Webshot {1}: {0}", "Joining Thread", id))
T.Join()
Return _Bitmap
End Function
Friend Sub GenerateImage()
LogIt(String.Format("Webshot {1}: {0}", "Instantiating Web Browser", id))
Dim _WebBrowser As New WebBrowser()
_WebBrowser.ScrollBarsEnabled = False
LogIt(String.Format("Webshot {1}: {0}", "Navigating", id))
_WebBrowser.Navigate(_URL)
AddHandler _WebBrowser.DocumentCompleted, AddressOf WebBrowser_DocumentCompleted
'AddHandler _WebBrowser.
While _WebBrowser.ReadyState <> WebBrowserReadyState.Complete
Application.DoEvents()
End While
LogIt(String.Format("Webshot {1}: {0}", "Disposing", id))
_WebBrowser.Dispose()
End Sub
Private Sub WebBrowser_DocumentCompleted(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
LogIt(String.Format("Webshot {1}: {0}", "Document load complete", id))
Dim _WebBrowser As WebBrowser = DirectCast(sender, WebBrowser)
_WebBrowser.ClientSize = New Size(Me._BrowserWidth, Me._BrowserHeight)
_WebBrowser.ScrollBarsEnabled = False
_Bitmap = New Bitmap(_WebBrowser.Bounds.Width, _WebBrowser.Bounds.Height)
_WebBrowser.BringToFront()
_WebBrowser.DrawToBitmap(_Bitmap, _WebBrowser.Bounds)
_PageTitle = _WebBrowser.DocumentTitle
LogIt(String.Format("Webshot {1}: {0}", "About to capture bitmap", id))
_Bitmap = DirectCast(_Bitmap.GetThumbnailImage(_BrowserWidth, _BrowserHeight, Nothing, IntPtr.Zero), Bitmap)
LogIt(String.Format("Webshot {1}: {0}", "Bitmap captured", id))
End Sub
和我看到的日志条目:
2010 01 19 02:21:01 > Starting Process
2010 01 19 02:21:01 > Capture 229 Processing: http://www.obfuscated.com/
2010 01 19 02:21:01 > Capture 229 Found capture db record
2010 01 19 02:21:01 > Webshot f7710f41-cac0-4ed1-93df-020620257c91: Instantiated
2010 01 19 02:21:01 > Capture 229 Requesting image
2010 01 19 02:21:01 > Webshot f7710f41-cac0-4ed1-93df-020620257c91: Getting Image
2010 01 19 02:21:01 > Webshot f7710f41-cac0-4ed1-93df-020620257c91: Starting Thread
2010 01 19 02:21:01 > Webshot f7710f41-cac0-4ed1-93df-020620257c91: Joining Thread
I wonder if someone can help me - I've been programming VB.Net for a long time but have rarely had to do much threading in ASP.Net.
I'm attempting to take "screenshots" of websites using an in-memory browser. These images are then logged in a DB and written to the local file system.
When I run it on my local server, it all works fine. When I run it in a shared hosting environment, it's all fine up until I do a thread.join at which point either the target thread terminates immediately or gets stuck (no further logging info is received from either thread). I've attached the log below
The crucial code is also attached but in short it does:
For each url, start a new thread and thread.join to it. The new thread will load the browser and begin navigation. it will then noop until the browser load has completed before returning the bitmap image generated (next step).
On browser load completion, an event fires. The handler captures the bitmap image from the browser and writes it to a local.
I've done some googling and can't find a lot of related information - I have found common shared hosting problems and have made sure I've got them covered (eg allowing partially trusted callers, signing assemblies, etc...)
I'd appreciate it if anyone with knowledge on this topic would be kind enough to point me in the right direction.
Many thanks
NB: I'm aware that at present it's going to be very slow as it's processing images sequentially - But until I can get it to work on one thread, I have no chance of getting it working on multiple threads.
This is largely mangled together from code samples and I haven't even begun to tidy it up / organise it better so apologies for the slightly messy code.
Public Function GetWebsiteImage(ByVal URL As String, Optional ByVal BrowserWidth As Integer = 1280, Optional ByVal BrowserHeight As Integer = 1024) As Bitmap
LogIt(String.Format("Webshot {1}: {0}", "Getting Image", id))
_URL = URL
_BrowserHeight = BrowserHeight
_BrowserWidth = BrowserWidth
Dim T As Thread
T = New Thread(New ThreadStart(AddressOf GenerateImage))
T.SetApartmentState(ApartmentState.STA)
'T.IsBackground = True
LogIt(String.Format("Webshot {1}: {0}", "Starting Thread", id))
T.Start()
'*** THIS IS THE LAST LOG ENTRY I SEE ***
LogIt(String.Format("Webshot {1}: {0}", "Joining Thread", id))
T.Join()
Return _Bitmap
End Function
Friend Sub GenerateImage()
LogIt(String.Format("Webshot {1}: {0}", "Instantiating Web Browser", id))
Dim _WebBrowser As New WebBrowser()
_WebBrowser.ScrollBarsEnabled = False
LogIt(String.Format("Webshot {1}: {0}", "Navigating", id))
_WebBrowser.Navigate(_URL)
AddHandler _WebBrowser.DocumentCompleted, AddressOf WebBrowser_DocumentCompleted
'AddHandler _WebBrowser.
While _WebBrowser.ReadyState <> WebBrowserReadyState.Complete
Application.DoEvents()
End While
LogIt(String.Format("Webshot {1}: {0}", "Disposing", id))
_WebBrowser.Dispose()
End Sub
Private Sub WebBrowser_DocumentCompleted(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
LogIt(String.Format("Webshot {1}: {0}", "Document load complete", id))
Dim _WebBrowser As WebBrowser = DirectCast(sender, WebBrowser)
_WebBrowser.ClientSize = New Size(Me._BrowserWidth, Me._BrowserHeight)
_WebBrowser.ScrollBarsEnabled = False
_Bitmap = New Bitmap(_WebBrowser.Bounds.Width, _WebBrowser.Bounds.Height)
_WebBrowser.BringToFront()
_WebBrowser.DrawToBitmap(_Bitmap, _WebBrowser.Bounds)
_PageTitle = _WebBrowser.DocumentTitle
LogIt(String.Format("Webshot {1}: {0}", "About to capture bitmap", id))
_Bitmap = DirectCast(_Bitmap.GetThumbnailImage(_BrowserWidth, _BrowserHeight, Nothing, IntPtr.Zero), Bitmap)
LogIt(String.Format("Webshot {1}: {0}", "Bitmap captured", id))
End Sub
and the log entries I see:
2010 01 19 02:21:01 > Starting Process
2010 01 19 02:21:01 > Capture 229 Processing: http://www.obfuscated.com/
2010 01 19 02:21:01 > Capture 229 Found capture db record
2010 01 19 02:21:01 > Webshot f7710f41-cac0-4ed1-93df-020620257c91: Instantiated
2010 01 19 02:21:01 > Capture 229 Requesting image
2010 01 19 02:21:01 > Webshot f7710f41-cac0-4ed1-93df-020620257c91: Getting Image
2010 01 19 02:21:01 > Webshot f7710f41-cac0-4ed1-93df-020620257c91: Starting Thread
2010 01 19 02:21:01 > Webshot f7710f41-cac0-4ed1-93df-020620257c91: Joining Thread
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当您在本地服务器上运行它时,您是指 ASP.NET 个人 Web 服务器还是本地安装的 IIS?前者甚至无法与 IIS 相比,因为它作为交互式 Windows 应用程序运行,而对于后者,您将作为没有 UI 的服务运行,并且线程的行为由 IIS 严格控制。
您可以尝试在 Page 指令上设置 aspcompat="true",但更有可能的是,托管公司已配置 IIS 工作进程 ping,这将终止在定义的时间段内无响应的线程。
最重要的是,WebBrowser 控件(以及它所包装的 SHDocVw ActiveX 控件)并非设计用于在非交互式服务进程中工作,并且您可能会在尝试使其工作时遇到困难。不幸的是,我不知道有任何更安全的替代方案。
When you are running it on your local server, do you mean the ASP.NET personal web server or a local installation of IIS? The former is not even comparable to IIS because it runs as an interactive Windows application whereas with the latter you'll be running as a service which can have no UI and the behavior of threads is governed strictly by IIS.
You could try setting aspcompat="true" on the Page directive, but more likely than not, the hosting company has configured IIS worker process pinging which will terminate threads that are unresponsive for a defined period of time.
The bottom line is that the WebBrowser control (and the SHDocVw ActiveX control that it wraps) is not designed to work in a non-interactive service process and you're likely in for an uphill climb trying to make it work. Unfortunately I don't know of any safer alternatives however.