Asynchronous Rust—如何在一个应用程序中使用同步和异步机箱

Asynchronous Rust—如何在一个应用程序中使用同步和异步机箱,asynchronous,rust,rust-tokio,rust-async-std,Asynchronous,Rust,Rust Tokio,Rust Async Std,我开始编写一个程序,使用crate和crate制作一个webscraping应用程序,我可以查看它的数据。在我花了很长时间构建这个程序之后,我才意识到合并同步和异步编程是个坏主意。我现在要做的是在应用程序打开时运行scraper(最好每小时一次) 现在,刮板直到应用程序关闭后才运行。我尝试使用Tokio的spawn创建一个单独的线程,在应用程序打开之前启动,但这不起作用,因为Crabler未来没有“发送”特性 我试图制作一个最小的功能程序,如下所示。title\u处理程序的功能不符合预期,但在其

我开始编写一个程序,使用crate和crate制作一个webscraping应用程序,我可以查看它的数据。在我花了很长时间构建这个程序之后,我才意识到合并同步和异步编程是个坏主意。我现在要做的是在应用程序打开时运行scraper(最好每小时一次)

现在,刮板直到应用程序关闭后才运行。我尝试使用Tokio的
spawn
创建一个单独的线程,在应用程序打开之前启动,但这不起作用,因为Crabler未来没有“发送”特性

我试图制作一个最小的功能程序,如下所示。
title\u处理程序
的功能不符合预期,但在其他方面,它很好地说明了我遇到的问题

允许WebScraper在应用程序打开时运行吗?如果是,怎么做

编辑:我尝试使用
task::spawn_blocking()
来运行应用程序,但它抛出了大量错误,包括德鲁伊没有实现trait
Send

use crabler::*;
use druid::widget::prelude::*;
use druid::widget::{Align, Flex, Label, TextBox};
use druid::{AppLauncher, Data, Lens, WindowDesc, WidgetExt};

const ENTRY_PREFIX: [&str; 1] = ["https://duckduckgo.com/?t=ffab&q=rust&ia=web"];

// Use WebScraper trait to get each item with the ".result__title" class
#[derive(WebScraper)]
#[on_response(response_handler)]
#[on_html(".result__title", title_handler)]

struct Scraper {}

impl Scraper {
    // Print webpage status
    async fn response_handler(&self, response: Response) -> Result<()> {
        println!("Status {}", response.status);
        Ok(())
    }

    async fn title_handler(&self, _: Response, el: Element) -> Result<()> {
        // Get text of element
        let title_data = el.children();
        let title_text = title_data.first().unwrap().text().unwrap();
        println!("Result is {}", title_text);
        Ok(())
    }
}

// Run scraper to get info from https://duckduckgo.com/?t=ffab&q=rust&ia=web
async fn one_scrape() -> Result<()> {
    let scraper = Scraper {};
    scraper.run(Opts::new().with_urls(ENTRY_PREFIX.to_vec()).with_threads(1)).await
}

#[derive(Clone, Data, Lens)]
struct Init {
    tag: String,
}


fn build_ui() -> impl Widget<Init> {
    // Search box
    let l_search = Label::new("Search: ");
    let tb_search = TextBox::new()
        .with_placeholder("Enter tag to search")
        .lens(Init::tag);
    let search = Flex::row()
        .with_child(l_search)
        .with_child(tb_search);

    // Describe layout of UI
    let layout = Flex::column()
        .with_child(search);
    
    Align::centered(layout)
}

#[async_std::main]
async fn main() -> Result<()> {
    // Describe the main window
    let main_window = WindowDesc::new(build_ui())
        .title("Title Tracker")
        .window_size((400.0, 400.0));

    // Create starting app state
    let init_state = Init {
        tag: String::from("#"),
    };

    // Start application
    AppLauncher::with_window(main_window)
        .launch(init_state)
        .expect("Failed to launch application");

    one_scrape().await
}
使用crabler::*;
使用druid::widget::prelude::*;
使用druid::widget::{Align,Flex,Label,TextBox};
使用druid:{AppLauncher,Data,Lens,WindowDesc,WidgetExt};
常量条目\u前缀:[&str;1]=[”https://duckduckgo.com/?t=ffab&q=rust&ia=web"];
//使用WebScraper trait获取带有“.result\uu title”类的每个项目
#[导出(WebScraper)]
#[关于响应(响应处理程序)]
#[在html(“.result\u title”,title\u handler)”上]
结构刮板{}
impl刮刀{
//打印网页状态
异步fn响应\u处理程序(&self,response:response)->结果{
println!(“状态{}”,response.Status);
好(())
}
异步fn title\u处理程序(&self,\u:Response,el:Element)->Result{
//获取元素的文本
设title_data=el.children();
让title_text=title_data.first().unwrap().text().unwrap();
println!(“结果为{}”,标题为文本);
好(())
}
}
//运行scraper从中获取信息https://duckduckgo.com/?t=ffab&q=rust&ia=web
异步fn one_scrape()->结果{
设scraper=scraper{};
scraper.run(Opts::new()。带有\u URL(条目\u前缀.to\u vec())。带有\u线程(1))。等待
}
#[衍生(克隆、数据、镜头)]
结构初始化{
标签:字符串,
}
fn build_ui()->impl小部件{
//搜索框
让l_search=Label::new(“search:”);
让tb_search=TextBox::new()
.带有占位符(“输入要搜索的标记”)
.lens(Init::tag);
let search=Flex::row()
.带子对象(l_搜索)
.有子女(tb_搜索);
//描述UI的布局
let layout=Flex::column()
.有子女(搜索);
对齐::居中(布局)
}
#[async_std::main]
异步fn main()->结果{
//描述主窗口
让main\u window=WindowDesc::new(build\u ui())
.title(“title Tracker”)
.窗口大小((400.0400.0));
//创建启动应用程序状态
让init_state=init{
tag:String::from(“#”),
};
//启动应用程序
AppLauncher::带_窗口(主_窗口)
.启动(初始状态)
.expect(“未能启动应用程序”);
等一等
}

使用东京时,您可以使用。其他异步框架提供类似的功能。尽管
spawn\u blocking
旨在与终止同步任务进行接口。要拥有一个主要独立于异步运行时的长时间运行线程(这里的情况似乎是这样?还不完全清楚),通常建议使用常规的
spawn