使用 React 和 Tauri (rust) 渲染数千/百万次

Posted

技术标签:

【中文标题】使用 React 和 Tauri (rust) 渲染数千/百万次【英文标题】:Render thousands/millions times with React and Tauri (rust) 【发布时间】:2021-08-17 16:48:19 【问题描述】:

我正在学习 Rust。我正在创建一个桌面应用程序,它读取 csv 文件中的数千/百万行数据,然后使用 tauri event 将它们一一传输。

结果:Rust 读取文件没有问题(不到 5 秒)。在前端,我的 React 应用程序似乎无法跟上事件的步伐。在屏幕上,altitude 值会间歇性更新。

React 是如何处理这种情况的?或者我做错了什么?

反应方:

// App.js

import  listen  from '@tauri-apps/api/event';
import  useEffect, useCallback, useState  from 'react';
import  invoke  from '@tauri-apps/api/tauri'

const App = () => 
  const [altitude, setAltitude] = useState("0");

  useEffect(() => 
    listen('rust-event', myCallback)
  , [])

  const myCallback = useCallback((e) => 
    console.log(e);
    setAltitude(e.payload);
  ,[])

  const handleClick = async () => 
    invoke('my_custom_command').catch(error => console.log(error));
  ;

  return (
    <div>
        <button onClick=handleClick>Click Me To Start Fetching!</button>
        <span>altitude</span>
    </div>
  );


export default App;

金牛座:

// main.rs
use arrow::csv;
use arrow::datatypes::DataType, Field, Schema;
use std::fs::File;
use std::sync::Arc;
use arrow::array::StringArray, ArrayRef;

#[tauri::command]
async fn my_custom_command(window: tauri::Window) 
  let schema = Schema::new(vec![
    Field::new("altitude", DataType::Utf8, false)
  ]);

  // Open file
  let file = File::open("src/data.csv").unwrap();

  // Get csv Reader using schema
  let mut csv = csv::Reader::new(file, Arc::new(schema), true, None, 1, None, None);

    // Loop through each row
    while let Some(m) = csv.next() 
      let n = m.unwrap();
      // Get reference of array of a column
      let col: &ArrayRef = n.column(0);
      // Cast the reference of array to array of string
      let col = col.as_any().downcast_ref::<StringArray>().unwrap();
      // Get value from the array using index
      let v = col.value(0);
      println!("", col.value(0));
      
      // Send each value through an event
      window
        .emit("rust-event", v)
        .expect("failed to emit");
    


fn main() 
  tauri::Builder::default()
    .invoke_handler(tauri::generate_handler![my_custom_command])
    .run(tauri::generate_context!())
    .expect("failed to run app");

【问题讨论】:

就像人们已经回答的那样,Rust 超级快,javascript 超级慢。即使只是生成几千个元素对 javascript 来说也是一个挑战,更不用说几十万或几百万了。我建议在您的前端切换方法。我最近做了一个简单的生活日历,打算每周显示一个盒子,但是前端对于这种方法来说太滞后了,所以我改为每年一个盒子,点击一个盒子会显示几周那个盒子。仅仅由于前端的限制,类似的解决方案可能更适合您。 【参考方案1】:

嗯,我猜 Rust 太快了 :) React 无法处理这个速度。

我使用 settimeout rust lib 减慢了事件发出的速度,我现在对此很满意。

// Before emit an event, delay it 100 microsecond;
set_timeout(Duration::from_micros(100)).await;

window
        .emit("rust-event", v)
        .expect("failed to emit");

【讨论】:

【参考方案2】:

我个人不建议您这样做,因为您可能会遇到堆栈溢出。

最好是批量发出它们,你可以填充一个本地缓冲区,当有 X 个元素时(或到达末尾),发出事件,并清除缓冲区。

示例

#[tauri::command]
async fn my_custom_command(window: tauri::Window) 
  // Your code
  // [...]

  // send 20 elements in the Vec (array)
  let should_trigger_at = 20;
  // local buffer
  let local_buffer: Vec<String> = Vec::new();

  // Loop through each row
  while let Some(m) = csv.next() 
    let n = m.unwrap();
    // Get reference of array of a column
    let col: &ArrayRef = n.column(0);
    // Cast the reference of array to array of string
    let col = col.as_any().downcast_ref::<StringArray>().unwrap();
    // Get value from the array using index
    let v = col.value(0);
    println!("", col.value(0));

    // add the value in the buffer
    local_buffer.push(col.value(0));

    if local_buffer.len() == should_trigger_at 
      // Send each value through an event
      window
        .emit("rust-event", local_buffer)
        .expect("failed to emit");

      // reset local buffer
      local_buffer = Vec::new();
    
  
  // if buffer not empty, lets emit the values
  if local_buffer.len() > 0 
    window
      .emit("rust-event", local_buffer)
      .expect("failed to emit");
  

  // [...]
  // Your code

请注意;这样做会将Array of String 发送到Webview 而不是String

【讨论】:

以上是关于使用 React 和 Tauri (rust) 渲染数千/百万次的主要内容,如果未能解决你的问题,请参考以下文章

Tauri 入门教程

Tauri 入门教程

Rust Tauri & OpenCV 写一个桌面摄像头

Rust Tauri & OpenCV 写一个桌面摄像头

Rust Tauri & OpenCV 写一个桌面摄像头

解决 Rust Tauri 1.0 构建时下载 WiX失败