通过Goroutines运行多个GTK WebKitWebViews

时间:2016-01-05 01:28:48

标签: go gtk3

我使用Go与gotk3webkit2库来尝试构建一个可以在WebKitWebView上下文中解析JavaScript的网络爬虫。

考虑到性能,我试图找出使用所有可用资源同时抓取(如果不是并行,使用多个处理器)的最佳方法。

GTK以及所有带线程和goroutines的东西对我来说都是新手。从gotk3 goroutines example读取,它指出:

  

原生GTK不是线程安全的,因此,其他goroutine可能无法使用gotk3的GTK绑定。相反,glib.IdleAdd()必须用于添加一个函数,以便在GTK主循环处于空闲状态时运行。

当我尝试在goroutine中运行一个创建新WebView的函数时,Go会发生恐慌并显示堆栈跟踪。我不确定为什么会发生这种情况,但我认为这与此评论有关。示例如下所示。

当前代码

这是我目前的代码,已经改编自webkit2 example

package main

import (
    "fmt"
    "github.com/gotk3/gotk3/glib"
    "github.com/gotk3/gotk3/gtk"
    "github.com/sourcegraph/go-webkit2/webkit2"
    "github.com/sqs/gojs"
)

func crawlPage(url string) {
    web := webkit2.NewWebView()

    web.Connect("load-changed", func(_ *glib.Object, i int) {
        loadEvent := webkit2.LoadEvent(i)

        switch loadEvent {
        case webkit2.LoadFinished:
            fmt.Printf("Load finished for: %v\n", url)

            web.RunJavaScript("window.location.hostname", func(val *gojs.Value, err error) {
                if err != nil {
                    fmt.Println("JavaScript error.")
                } else {
                    fmt.Printf("Hostname (from JavaScript): %q\n", val)
                }

                //gtk.MainQuit()
            })
        }
    })

    glib.IdleAdd(func() bool {
        web.LoadURI(url)
        return false
    })
}

func main() {
    gtk.Init(nil)

    crawlPage("https://www.google.com")
    crawlPage("https://www.yahoo.com")
    crawlPage("https://github.com")
    crawlPage("http://deelay.me/2000/http://deelay.me/img/1000ms.gif")

    gtk.Main()
}

似乎为每个URL创建一个新的WebView允许它们同时加载。根据gotk3示例,让glib.IdleAdd()在goroutine中运行,似乎没有任何效果(尽管我只做了视觉基准测试):

go glib.IdleAdd(func() bool { // Works
    web.LoadURI(url)
    return false
})

但是,尝试为每个crawlPage()电话创建一个goroutine会以恐慌结束:

go crawlPage("https://www.google.com") // Panics and shows stack trace

我可以毫无问题地在goroutine中运行web.RunJavaScript()

        switch loadEvent {
        case webkit2.LoadFinished:
            fmt.Printf("Load finished for: %v\n", url)

            go web.RunJavaScript("window.location.hostname", func(val *gojs.Value, err error) { // Works
                if err != nil {
                    fmt.Println("JavaScript error.")
                } else {
                    fmt.Printf("Hostname (from JavaScript): %q\n", val)
                }

                //gtk.MainQuit()
            })
        }

最佳方法?

我能想到的当前方法是:

  1. 生成新的WebView以抓取每个页面,如当前代码所示。跟踪打开的WebView数量,并连续删除和创建新WebView,或者重新使用最初创建的集合号,以便使用计算机上所有可用资源。这会在使用的处理器内核方面受到限制吗?
  2. #1的基本思想,但多次运行二进制文件(而不是在机器上运行一个gocrawler进程,有四个)来利用所有核心/资源。
  3. 在自己的goroutine中运行应用程序的GUI(gtk3)部分。然后,我可以将数据传递给其他goroutine,这些goroutine会进行自己繁重的处理,例如搜索内容。
  4. 如果可能的话,实际上同时运行此代码的最佳方法是什么,并最大限度地提高性能?

    更新

    方法1和方法2可能不合适,因为我通过生成~100个WebViews进行测试,它们似乎同步加载。

0 个答案:

没有答案