c#uwp:调度webview导航和捕获每个可用的逻辑cpu

问题描述:

我正在学习代码和做一个捕获谷歌街景screenshost的应用程序。许多截图。我想找到一种平行查询的方法。c#uwp:调度webview导航和捕获每个可用的逻辑cpu

在这里,在时间为单个查询的代码:

// prepare the html code string in a dictionary (I use street view in a iframe) 
Dictionary<int, string> htmlCode= SetUpURLListHD(); 

// prepare the webview and display it on a grid 
WebView saveWebView = new WebView(); 
saveWebView.Width = Width; 
saveWebView.Height = Height; 
TopGrid.Children.Add(saveWebView); 

// navigate to string, wait a moment until street view completely loaded, do a capture, save it to file m.jpg with custom function 
for (var m = 0; m < htmlCode.Count; m++) 
      { 
       saveWebView.NavigateToString(htmlCode[m]); 
       await Task.Delay(2000); 
       await saveWebView.CapturePreviewToStreamAsync(stream); 
       await SaveSSAsync(stream, m); 
      } 

我有16个逻辑CPU,RAM的64Go,和光纤连接。所以,我想要做的时间,直到16个查询。

对于这一点,我想我需要写16个函数来创建16个网页视图:

async Task ProcessURLHD1Async(string url, int i, int width, int height, ulong firstFrameSize) 
     { 
      try 
      { 
       WebView saveWebView1 = new WebView(); 
       saveWebView1.Width = width; 
       saveWebView1.Height = height; 
       TopGrid.Children.Add(saveWebView1); 
       ... 

二级功能:

async Task ProcessURLHD2Async(string url, int i, int width, int height, ulong firstFrameSize) 
     { 
      try 
      { 
       WebView saveWebView2 = new WebView(); 
       saveWebView2.Width = width; 
       saveWebView2.Height = height; 
       TopGrid.Children.Add(saveWebView2); 

等...

我不知道如果这是做到这一点的正确方法。 我现在正试图同时执行16个函数,当一个结束时,再次用下一个html代码(字典中编码的下一个街景视图图像)重新开始。 现在,没有结果。 欢迎任何帮助。

谢谢!

ps:这是我编码几周后的第一条消息,感谢所有在本网站上提供帮助的人,对我非常有用!

编辑:好的!我发现 !这很丑,但速度很快! :

// below namespace : 

    public static class DispatcherTaskExtensions 
    { 
     public static async Task<T> RunTaskAsync<T>(this CoreDispatcher dispatcher, 
      Func<Task<T>> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) 
     { 
      var taskCompletionSource = new TaskCompletionSource<T>(); 
      await dispatcher.RunAsync(priority, async() => 
      { 
       try 
       { 
        taskCompletionSource.SetResult(await func()); 
       } 
       catch (Exception ex) 
       { 
        taskCompletionSource.SetException(ex); 
       } 
      }); 
      return await taskCompletionSource.Task; 
     } 

     // There is no TaskCompletionSource<void> so we use a bool that we throw away. 
     public static async Task RunTaskAsync(this CoreDispatcher dispatcher, 
      Func<Task> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) => 
      await RunTaskAsync(dispatcher, async() => { await func(); return false; }, priority); 
    } 

//Call function on click 
private async void GetHDMT_Click(object sender, RoutedEventArgs e) 
     { 
      if (outputFolder == null) 
      { 
       var folderPicker = new Windows.Storage.Pickers.FolderPicker(); 
       folderPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.Desktop; 
       folderPicker.FileTypeFilter.Add("*"); 

       outputFolder = await folderPicker.PickSingleFolderAsync(); 
       if (outputFolder != null) 
       { 
        // Application now has read/write access to all contents in the picked folder 
        // (including other sub-folder contents) 
        Windows.Storage.AccessCache.StorageApplicationPermissions. 
        FutureAccessList.AddOrReplace("PickedFolderToken", outputFolder); 
       } 
       else 
       { 
       } 
      } 
      if (mylat.Count > 0) 
      { 

       await GetImagesAsyncHD(); 
      } 
     } 


private async Task GetImagesAsyncHD() 
     { 
// Make a list of html code with street view iframe. 
      var Width = 4000; 
      var Height = 2000; 
      var urls = SetUpURLListHD(Width, Height); 


      WebView saveWebView0 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView0); 
      WebView saveWebView1 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView1); 
      WebView saveWebView2 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView2); 
      WebView saveWebView3 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView3); WebView 
       saveWebView4 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView4); 
      WebView saveWebView5 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView5); 
      WebView saveWebView6 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView6); 
      WebView saveWebView7 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView7); WebView 
       saveWebView8 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView8); 
      WebView saveWebView9 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView9); 
      WebView saveWebView10 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView10); 
      WebView saveWebView11 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView11); 
      WebView saveWebView12 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView12); 
      WebView saveWebView13 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView13); 
      WebView saveWebView14 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView14); 
      WebView saveWebView15 = new WebView 
      { 
       Width = Width, 
       Height = Height 
      }; 
      TopGrid.Children.Add(saveWebView15); 
      List<Task> tasks = new List<Task>(); 
      Task t0 = Task.Run(async() => 
      { 
       for (var j=0; j<urls.Count; j=j+16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t0); 
      Task t1 = Task.Run(async() => 
      { 
       for (var j = 1; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t1); 
      Task t2 = Task.Run(async() => 
      { 
       for (var j = 2; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t2); 
      Task t3 = Task.Run(async() => 
      { 
       for (var j = 3; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t3); 
      Task t4 = Task.Run(async() => 
      { 
       for (var j = 4; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t4); 
      Task t5 = Task.Run(async() => 
      { 
       for (var j = 5; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t5); 
      Task t6 = Task.Run(async() => 
      { 
       for (var j = 6; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t6); 
      Task t7 = Task.Run(async() => 
      { 
       for (var j = 7; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t7); 
      Task t8 = Task.Run(async() => 
      { 
       for (var j = 8; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t8); 
      Task t9 = Task.Run(async() => 
      { 
       for (var j = 9; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t9); 
      Task t10 = Task.Run(async() => 
      { 
       for (var j = 10; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t10); 
      Task t11 = Task.Run(async() => 
      { 
       for (var j = 11; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t11); 
      Task t12 = Task.Run(async() => 
      { 
       for (var j = 12; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t12); 
      Task t13 = Task.Run(async() => 
      { 
       for (var j = 13; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t13); 
      Task t14 = Task.Run(async() => 
      { 
       for (var j = 14; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t14); 
      Task t15 = Task.Run(async() => 
      { 
       for (var j = 15; j < urls.Count; j = j + 16) 
        await ProcessURLHD0Async(urls[j], j, Width, Height, firstFrameSize, saveWebView0, outputFolder); 
      }); 
      tasks.Add(t15); 

      await Task.WhenAll(tasks); 
     } 

public static async Task ProcessURLHD0Async(string url, int i, int width, int height, ulong firstFrameSize, WebView saveWeb, StorageFolder folder) 
     { 
      try 
      { 
       var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher; 
       await dispatcher.RunAsync(CoreDispatcherPriority.Normal,() => 
       { 
        saveWeb.NavigateToString(url); 
       }); 


       await Task.Delay(3000); 
       var kk = 0; 
       var pixelised = true; 

       while (pixelised == true) 
       { 
        ulong thissize = await CaptureAndSave(saveWeb, i, folder); 
        if ((thissize > 0.7 * firstFrameSize) || kk > 5) 
        { 
         pixelised = false; 
        } 
        else 
        { 
         await Task.Delay(1000); 
         kk = kk + 1; 
        } 
       } 

      } 
      catch (Exception) 
      { 
       throw; 
      } 
     } 

public static async Task<ulong> CaptureAndSave(WebView webv, int i, StorageFolder folder) 
     { 
      ulong size = 0; 
      SoftwareBitmap softwareBitmap = null; 
      InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream(); 
      BitmapDecoder decoder = null; 
      // Changes to imageElement must happen on the UI thread. 
      await webv.Dispatcher.RunTaskAsync(async() => 
      {    
       await webv.CapturePreviewToStreamAsync(stream); 
       decoder = await BitmapDecoder.CreateAsync(stream); 
       softwareBitmap = await decoder.GetSoftwareBitmapAsync(); 
      }); 

       StorageFile file_Save = await folder.CreateFileAsync(i + ".jpg", CreationCollisionOption.ReplaceExisting); 
       if (file_Save != null) 
       { 
        using (var streamF = await file_Save.OpenAsync(FileAccessMode.ReadWrite)) 
        { 
         //StorageFile file_Save = await outputFolder.CreateFileAsync(i + "_" + equals + "_" + size + ".jpg", CreationCollisionOption.ReplaceExisting); 
         //< encoder to save > 
         BitmapEncoder encoder = await BitmapEncoder.CreateAsync(Windows.Graphics.Imaging.BitmapEncoder.JpegEncoderId, streamF); 
         encoder.SetSoftwareBitmap(softwareBitmap); 
         await encoder.FlushAsync(); 
         //</ encoder to save > 
         //-</ Save Bitmap as File >- 
        } 
       } 
       var basicProperties = await file_Save.GetBasicPropertiesAsync(); 
       size = basicProperties.Size; 
       while (size < 21) 
       { 
        await Task.Delay(100); 
        basicProperties = await file_Save.GetBasicPropertiesAsync(); 
        size = basicProperties.Size; 
       } 
       stream.Dispose(); 
       softwareBitmap.Dispose(); 


      return size; 
     } 

结果:118秒捕获(总数= 139Mo)在20秒内对278没有平行!!!最大使用5 GB内存。

编辑2: 要快...有上面代码中的错误,我总是用Savewebview0,当我纠正(Savewebview1,Savewebview2 ....)结果是... 400数秒 所有的工作是由主线我想,我需要在其他线程创建webviews,但我认为这是不可能的... 如果任何人有一个想法... :(

好吧,经过多次审判,我有很好的效果

的代码是在这里谁想要使用它:

public static class DispatcherTaskExtensions 
    { 
     public static async Task<T> RunTaskAsync<T>(this CoreDispatcher dispatcher, 
      Func<Task<T>> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) 
     { 
      var taskCompletionSource = new TaskCompletionSource<T>(); 
      await dispatcher.RunAsync(priority, async() => 
      { 
       try 
       { 
        taskCompletionSource.SetResult(await func()); 
       } 
       catch (Exception ex) 
       { 
        taskCompletionSource.SetException(ex); 
       } 
      }); 
      return await taskCompletionSource.Task; 
     } 

     // There is no TaskCompletionSource<void> so we use a bool that we throw away. 
     public static async Task RunTaskAsync(this CoreDispatcher dispatcher, 
      Func<Task> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) => 
      await RunTaskAsync(dispatcher, async() => { await func(); return false; }, priority); 
    } 

以上代码位于命名空间解除之下。

private async void GetHDMT2_Click(object sender, RoutedEventArgs e) 
    { 
     if (outputFolder == null) 
     { 
      var folderPicker = new Windows.Storage.Pickers.FolderPicker(); 
      folderPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.Desktop; 
      folderPicker.FileTypeFilter.Add("*"); 

      outputFolder = await folderPicker.PickSingleFolderAsync(); 
      if (outputFolder != null) 
      { 
       Windows.Storage.AccessCache.StorageApplicationPermissions. 
       FutureAccessList.AddOrReplace("PickedFolderToken", outputFolder); 
      } 
      else 
      { 
      } 
     } 
     if (mylat.Count > 0) 
     { 
      await GetImagesAsyncHD2(); 
     } 
    } 

    private async Task GetImagesAsyncHD2() 
    { 
     // Make a dictionary with html code string (with street view iframe inside . 
     var Width = 4000; 
     var Height = 2000; 
     Dictionary<int,string> urls = SetUpURLListHD(Width, Height); 

     //Code to estimate time for completely loading the first page (compute a time to use in await task.delay, and the size of first frame nextly used to know if image is pixelised or not (street view fisnish loading or not) 
     SoftwareBitmap softwareBitmap = null; 
     InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream(); 
     BitmapDecoder decoder = null; 
     var k = 0; 
     WebView saveWebView = new WebView(); 
     saveWebView.Width = Width; 
     saveWebView.Height = Height; 
     TopGrid.Children.Add(saveWebView); 
     var stopwatch = new Stopwatch(); 
     stopwatch.Start(); 
     long elapsed_time=0; 
     saveWebView.NavigateToString(urls[0]); 
     await Task.Delay(10); 
     bool equals = false; 
     bool findeq = false; 
     int t = 0; 
     int countTrue = 0; 
     bool checka = false; 
     List<byte[]> bytes400a = null; 
     List<byte[]> bytes400b = null; 
     await saveWebView.CapturePreviewToStreamAsync(stream); 
     decoder = await BitmapDecoder.CreateAsync(stream); 
     softwareBitmap = await decoder.GetSoftwareBitmapAsync(); 
     bytes400a = GetPixelsP(softwareBitmap); 
     while (countTrue < 20) 
     { 
      await Task.Delay(50); 
      if (checka) 
      { 
       await saveWebView.CapturePreviewToStreamAsync(stream); 
       decoder = await BitmapDecoder.CreateAsync(stream); 
       softwareBitmap = await decoder.GetSoftwareBitmapAsync(); 
       bytes400a = GetPixelsP(softwareBitmap); 
       checka = false; 
      } 
      else 
      { 
       await saveWebView.CapturePreviewToStreamAsync(stream); 
       decoder = await BitmapDecoder.CreateAsync(stream); 
       softwareBitmap = await decoder.GetSoftwareBitmapAsync(); 
       bytes400b = GetPixelsP(softwareBitmap); 
       checka = true; 
      } 
      t = t + 1; 
      equals = EqualsByte(bytes400a, bytes400b); 
      if (equals) 
      { 
       countTrue = countTrue + 1; 
      } 
      if ((equals) && (findeq == false)) 
      { 
       k = t; 
       elapsed_time = stopwatch.ElapsedMilliseconds; 
       SlidetimeCompute.Value = elapsed_time; 
       findeq = true; 
      } 
      if (equals == false) { findeq = false; } 
     } 
     stopwatch.Stop(); 
     var elapsed_timeForTest = stopwatch.ElapsedMilliseconds; 
     await SaveSSAsync(softwareBitmap, "0"); 
     ulong firstFrameSize = await GetSizePicAsync("0"); 
     TopGrid.Children.Remove(saveWebView); 
     stream.Dispose(); 
     softwareBitmap.Dispose(); 

     double timeTowait = (double)elapsed_time; 
     timeTowait = Math.Round(timeTowait/4); 

     // prepare somes grids 
     var nj = 7; 
     List<Grid> grids = new List<Grid>(); 
     Grid tmpgrid0 = new Grid(); 
     grids.Add(tmpgrid0); 
     Grid tmpgrid1 = new Grid(); 
     grids.Add(tmpgrid1); 
     Grid tmpgrid2 = new Grid(); 
     grids.Add(tmpgrid2); 
     Grid tmpgrid3 = new Grid(); 
     grids.Add(tmpgrid3); 
     Grid tmpgrid4 = new Grid(); 
     grids.Add(tmpgrid4); 
     Grid tmpgrid5 = new Grid(); 
     grids.Add(tmpgrid5); 
     Grid tmpgrid6 = new Grid(); 
     grids.Add(tmpgrid6); 
     Grid tmpgrid7 = new Grid(); 
     grids.Add(tmpgrid7); 
     Grid tmpgrid8 = new Grid(); 
     grids.Add(tmpgrid8); 
     Grid tmpgrid9 = new Grid(); 
     grids.Add(tmpgrid9); 
     Grid tmpgrid10 = new Grid(); 
     grids.Add(tmpgrid10); 
     Grid tmpgrid11 = new Grid(); 
     grids.Add(tmpgrid11); 
     Grid tmpgrid12 = new Grid(); 
     grids.Add(tmpgrid12); 
     Grid tmpgrid13 = new Grid(); 
     grids.Add(tmpgrid13); 
     Grid tmpgrid14 = new Grid(); 
     grids.Add(tmpgrid14); 
     Grid tmpgrid15 = new Grid(); 
     grids.Add(tmpgrid15); 
     Grid tmpgrid16 = new Grid(); 
     grids.Add(tmpgrid16); 

     // add tasks 
     List<Task> tasks = new List<Task>(); 
     for (var i = 1; i < nj+1; i++) 
     { 
      TopGrid.Children.Add(grids[i]); 
      await Task.Delay(1000); 
      tasks.Add(await AddTaskAsync(i, nj, Width, Height, firstFrameSize,outputFolder, grids[i], urls, timeTowait) 
       ); 
     } 
     // await all tasks 
     await Task.WhenAll(tasks); 
    } 

    public static async Task<Task> AddTaskAsync(int i, int nj, int width, int height, ulong firstFrameSize, StorageFolder folder, Grid grid, Dictionary<int, string> urls, double timeTowait) 
    { 
     var t0 = Task.Run(async() => 
     { 
      for (var j = i; j < urls.Count; j = j + nj) 
       await ProcessURLHD1Async(urls[j], j, width, height, firstFrameSize, folder, grid, timeTowait); 
     }); 
     await Task.Delay(200); 
     return t0; 
    } 

    public static async Task ProcessURLHD1Async(string url, int i, int width, int height, ulong firstFrameSize, StorageFolder folder, Grid grid, double timeTowait) 
    { 
     try 
     { 
      var Dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher; 
      await grid.Dispatcher.RunTaskAsync(async() => 
      { 
       var saveWeb1 = new WebView(WebViewExecutionMode.SeparateThread) 
       { 
        Width = width, 
        Height = height 
       }; 
       grid.Children.Add(saveWeb1); 
       saveWeb1.NavigateToString(url); 
       //give street view some delay to load 
       await Task.Delay((int)timeTowait*5); 
       var kk = 0; 
       var pixelised = true; 
       SoftwareBitmap softwareBitmap = null; 
       InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream(); 
       BitmapDecoder decoder = null; 

       while (pixelised == true) 
       { 
        await saveWeb1.CapturePreviewToStreamAsync(stream); 
        decoder = await BitmapDecoder.CreateAsync(stream); 
        softwareBitmap = await decoder.GetSoftwareBitmapAsync(); 


        StorageFile file_Save = await folder.CreateFileAsync(i + ".jpg", CreationCollisionOption.ReplaceExisting); 
        if (file_Save != null) 
        { 
         using (var streamF = await file_Save.OpenAsync(FileAccessMode.ReadWrite)) 
         { 
          BitmapEncoder encoder = await BitmapEncoder.CreateAsync(Windows.Graphics.Imaging.BitmapEncoder.JpegEncoderId, streamF); 
          encoder.SetSoftwareBitmap(softwareBitmap); 
          await encoder.FlushAsync(); 
         } 
        } 
        var basicProperties = await file_Save.GetBasicPropertiesAsync(); 
        ulong thissize = basicProperties.Size; 
        while (thissize < 21) 
        { 
         await Task.Delay(100); 
         basicProperties = await file_Save.GetBasicPropertiesAsync(); 
         thissize = basicProperties.Size; 
        } 

        if ((thissize > 0.7 * firstFrameSize) || kk > 10) 
        { 
         pixelised = false; 
        } 
        else 
        { 
         await Task.Delay((int)timeTowait*2); 
         kk = kk + 1; 
        } 
       } 
       stream.Dispose(); 
       softwareBitmap.Dispose(); 
       grid.Children.Clear(); 

      }); 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 

最好的结果是与7个任务并行。为什么是7?不知道。 使用单一任务,在304秒内获得118次(141 Mo),7次任务58秒! 现在,我需要找到一种方法来使代码适应不同的硬件和互联网连接。