Как повторно использовать / передавать агент Ureq в мои темы - PullRequest
0 голосов
/ 09 января 2020

Пожалуйста, примите во внимание этот код ржавчины,

use scoped_threadpool::Pool;
use std::thread;

const BASE_URL: &str = "https://www.bing.com/search?q=";

struct my_struct<'a> {
    url: &'a str,
    id: i16,
}

impl my_struct<'_> {
    fn doGet(&self) -> bool {
        let resp = ureq::get(self.url).timeout_connect(5_000).call();
        if !resp.ok() {
            return false;
        } else {
            return resp.ok();
        }
    }
}

fn main() {
    println!("Hello, world!");
    let our_vec = (1..11).collect::<Vec<_>>();
    let mut pool = Pool::new(3);

    pool.scoped(|scoped| {
        for entry in our_vec {
            scoped.execute(move || {
                let url = format!("{}{}", BASE_URL, entry);
                let this_item = my_struct {
                    url: &url,
                    id: entry,
                };
                let our_bool = this_item.doGet();
                println!("{} status: {}", entry, our_bool);
            });
        }
    });
}

Он генерирует 10 URL-адресов и делает минимальный GET для каждого, и это работает. Тем не менее, приведенный выше код использует новое соединение для каждого URL-адреса, и, следовательно, слишком дорого для моей реальной ситуации. ureq, кажется, имеет Агент , который поддерживает пул соединений.

Итак, я попытался:

const BASE_URL: &str = "https://www.bing.com/search?q=";
use scoped_threadpool::Pool;
use std::thread;

struct my_struct<'a> {
    url: &'a str,
    id: i16,
}

impl my_struct<'_> {
    fn doGet(&self) -> bool {
        let resp = ureq::get(self.url).timeout_connect(5_000).call();
        if !resp.ok() {
            return false;
        } else {
            return resp.ok();
        }
    }
    fn doGet_withAgent(&self, some_Agent: &ureq::Agent) -> bool {
        return true;
    }
}

fn main() {
    println!("Hello, world!");
    let our_vec = (1..11).collect::<Vec<_>>();
    let mut pool = Pool::new(3);
    let agent = ureq::Agent::new();

    pool.scoped(|scoped| {
        for entry in our_vec {
            scoped.execute(move || {
                let url = format!("{}{}", BASE_URL, 3);
                let this_item = my_struct {
                    url: &url,
                    id: entry,
                };
                //let our_bool = this_item.doGet();
                let our_bool = this_item.doGet_withAgent(&agent);
                println!("{} status: {}", entry, our_bool);
            });
        }
    });
}

, но не могу понять, что это правильно:


error[E0382]: use of moved value: `agent`
  --> src/main.rs:33:28
   |
33 |             scoped.execute(move || {
   |                            ^^^^^^^ value moved into closure here, in previous iteration of loop
...
40 |                 let our_bool = this_item.doGet_withAgent(&agent);
   |                                                           ----- use occurs due to use in closure

Моя цель - повторно использовать мои соединения. Какой идиоматический c способ добиться этого?

Редактировать 1

const BASE_URL: &str = "https://www.bing.com/search?q=";
use scoped_threadpool::Pool;
use std::thread;

struct my_struct<'a> {
    url: &'a str,
    id: i16,
}

impl my_struct<'_> {
    fn doGet(&self) -> bool {
        let resp = ureq::get(self.url).timeout_connect(5_000).call();
        if !resp.ok() {
            return false;
        } else {
            return resp.ok();
        }
    }
    fn doGet_withAgent(&self, some_Agent: &ureq::Agent) -> bool {
        let resp = some_Agent.get(self.url).timeout_connect(5_000).call();
        return true;
    }
}

fn main() {
    println!("Hello, world!");
    let our_vec = (1..11).collect::<Vec<_>>();
    let mut pool = Pool::new(3);
    let mut agent = ureq::Agent::new();

    pool.scoped(|scoped| {
        for entry in our_vec {
            let agent = &agent;
            scoped.execute(move || {
                let url = format!("{}{}", BASE_URL, entry);
                let this_item = my_struct {
                    url: &url,
                    id: entry,
                };
                let our_bool = this_item.doGet_withAgent(agent);
                println!("{} status: {}", entry, our_bool);
            });
        }
    });
}

Редактировать 2

Поэтому я завернул агент в ARC, все еще используя новые соединения для последовательных запросов.

const BASE_URL: &str = "https://www.google.com/search?q=";
use scoped_threadpool::Pool;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;

struct my_struct<'a> {
    url: &'a str,
    id: i16,
}

impl my_struct<'_> {
    fn doGet(&self) -> bool {
        let resp = ureq::get(self.url).timeout_connect(5_000).call();
        return resp.ok();
    }

    //fn doGet_withAgent(&self, some_Agent: ureq::Agent) -> bool {
    //fn doGet_withAgent(&self, some_mutex: &std::sync::Arc)-> bool{
    fn doGet_withAgent(&self, some_mutex: Arc<Mutex<ureq::Agent>>) -> bool {
        let mut guard = some_mutex.lock().unwrap();
        let resp = guard.head(self.url).timeout_connect(5_000).call();
        return resp.ok();
    }
}

fn main() {
    println!("Hello, world!");
    let our_vec = (1..11).collect::<Vec<_>>();
    let mut pool = Pool::new(3);
    let agent = Arc::new(Mutex::new(ureq::Agent::new()));

    pool.scoped(|scoped| {
        for entry in our_vec {
            let agent_clone = agent.clone();
            scoped.execute(move || {
                let url = format!("{}{}", BASE_URL, 3);
                let this_item = my_struct {
                    url: &url,
                    id: entry,
                };
                let our_bool = this_item.doGet_withAgent(agent_clone);
                println!("{} status: {}", entry, our_bool);
            });
        }
    });
}

Ответы [ 2 ]

0 голосов
/ 10 января 2020

в отличие от golang, где http-клиенты безопасны для одновременного использования несколькими программами - я узнал, что каждая реализация ржавчины может не поддерживать потоки / быть безопасной.

Затем найдено isah c, его HttpClient полностью поточно-ориентирован. Гораздо проще, не нужно ARC мьютексов, поскольку он может работать с приглушенной ссылкой на client:

Car go .toml

[dependencies]
scoped_threadpool = "0.1.9"
isahc = "0.8.2"

Код:

const BASE_URL: &str = "https://www.BinG.com/search?q=";
use scoped_threadpool::Pool;
use isahc::prelude::*;

struct my_struct<'a> {
    url: &'a str,
    id: i16,
}

impl my_struct<'_> {
    fn doGet_withClient(&self, incoming_client: &isahc::HttpClient) -> bool {
        let response;
        match incoming_client.get(self.url) {
            Ok(resp) => {
                response = resp;
            }
            _ => {
                return false;
            }
        }
        return response.status().is_success();

        return false;
    }
}

fn main() {
    println!("Hello, world!");
    let our_vec = (1..11).collect::<Vec<_>>();
    let mut pool = Pool::new(4);
    let client;
    match HttpClient::new() {
        Ok(this_thing) => {
            client = this_thing;
        }
        _ => {
            panic!("could not get http client thingy");
        }
    }

    pool.scoped(|scoped| {
        for entry in our_vec {
            let new_client = &client;
            scoped.execute(move || {
                let url = format!("{}{}", BASE_URL, entry);
                let this_item = my_struct {
                    url: &url,
                    id: entry,
                };

                let our_bool = this_item.doGet_withClient(new_client);
                println!("{} status: {}", entry, our_bool);
            });
        }
    });
}

Запуск:

Hello, world!
3 status: true
4 status: true
2 status: true
1 status: true
5 status: true
6 status: true
8 status: true
9 status: true
10 status: true
7 status: true
0 голосов
/ 10 января 2020

Я закончил тем, что переключился на reqwest с ureq

Автомобиль go .toml

[dependencies]
scoped_threadpool = "0.1.9"
reqwest = { version = "0.10", features = ["blocking"] }
...
const BASE_URL: &str = "https://www.BinG.com/search?q=";
use scoped_threadpool::Pool;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;

struct my_struct<'a> {
    url: &'a str,
    id: i16,
}

impl my_struct<'_> {
    fn doGet_withAgent(&self, some_mutex: Arc<Mutex<reqwest::blocking::Client>>) -> bool {
        let resp;
        let mut guard = some_mutex.lock().unwrap();
        match guard.head(self.url).send() {
            Ok(in_here) => {
                resp = in_here;
            }
            _ => {
                return false;
            }
        }

        match resp.status().as_u16() {
            200 => {
                return true;
            }
            _ => (),
        }

        return false;
    }
}

fn main() {
    println!("Hello, world!");
    let our_vec = (1..11).collect::<Vec<_>>();
    let mut pool = Pool::new(2);

    let agent = Arc::new(Mutex::new(reqwest::blocking::Client::new()));
    pool.scoped(|scoped| {
        for entry in our_vec {
            let agent_clone = agent.clone();
            scoped.execute(move || {
                let url = format!("{}{}", BASE_URL, entry);
                let this_item = my_struct {
                    url: &url,
                    id: entry,
                };

                let our_bool = this_item.doGet_withAgent(agent_clone);
                println!("{} status: {}", entry, our_bool);
            });
        }
    });
}

Это ведет себя хорошо с уважением к повторному использованию соединения, хотя я не уверен, что многопоточность очень поможет:

Hello, world!
1 status: true
2 status: true
3 status: true
4 status: true
5 status: true
6 status: true
7 status: true
8 status: true
9 status: true
10 status: true

Выполнение кажется последовательным, не уверен, если я увижу разницу, если я переключусь на async вместо blocking reqwest.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...