Dart-使长时间运行的同步功能异步 [英] Dart - make long running synchronous function asynchronous

查看:163
本文介绍了Dart-使长时间运行的同步功能异步的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数,可能需要花费几秒钟来执行,并且它是同步的。是否:

I have a function that might take a few seconds to execute, and it is synchronous. Does:

String slowFunction() { ... }
...
Future<String>(() => slowFunction());

将其更改为异步吗?

如果

Future<void> anotherFunction() async {
  // other async calls with Futures and await
  ...
  final result = await Future<String>(() => slowFunction());
  print(result);
  ...
  // do something else with result
}

创建 Future 只是立即在其上等待 await 似乎有些奇怪。我应该只调用该函数吗?我猜这有点屈服并允许其他代码之前执行,但是这样的代码有什么用吗?

Seems kind of strange to create a Future only to immediately await on it. Should I just call the function? I guess it kind of 'yields' and allows other code to be executed before, but does such code have any use?

推荐答案

进行本质上是同步的过程并将其打扮成异步过程是没有意义的。这是由于不仅在Dart中,而且在一般情况下,异步性(更通常称为并发)如何工作。并发只是一个编程技巧,它使多个操作在同一线程中相互交错运行,从而产生了真正的并行性(即不同线程或进程同时运行的地方)的幻觉。这样一来,通常在等待资源的过程中通常会阻塞的进程将被推迟到以后,直到程序继续执行其他操作为止。

There is no point in making a process that is inherently synchronous and dressing it up as an asynchronous one. This is due to how asynchronicity (more generally referred to as "concurrency") works, not just in Dart but in general. Concurrency is just a programming trick to make multiple operations run interleaved with each other in the same thread, giving the illusion of true parallelism (which is where different threads or processes run simultaneously). This allows processes that would normally block while waiting for a resource to be put off until later as the program carries on with other things.

如果您要执行同步进程会由于正在积极完成工作而阻塞 ,或者程序将像执行异步代码一样以其他方式阻塞程序,否则程序将阻塞同样长的时间,但以后会阻塞。无论哪种方式,您仍然会使用长时间运行的程序来阻塞程序。

If you were to take a synchronous process that blocks due to work being actively done, either the program will block anyway as the "async" code executes just as it would otherwise do or the program will block just as long but at a later time. Either way, you are still blocking your program with a long-running process.

以以下示例为例,这就是您要问的问题:采用长时间运行的程序并将其包装在 Future 中,从而使其异步:

Take the following for example, which is what you ask: take a long-running process and wrap it in a Future, thus making it "asynchronous":

String slowFunction() { ... }
...
String result = await Future(slowFunction);

在正常并发情况下,这将放置 slowFunction 在异步队列中。下次程序出现一些停机时间时(例如,在两次UI绘制调用之间),它将将该函数从队列中拉出并进行处理。还有 that 当函数执行时它会阻塞2-3秒。

In normal concurrency, this will put slowFunction in the async queue. The next time the program has some downtime (in between UI draw calls, for example) it will pull that function out of the queue and process it. And thats when it will block for 2-3 seconds while the function executes.

在Dart中,它的工作原理略有不同。因为 slowFunction 不是 async 函数并且不会 await 任何东西,Dart都会尝试同步运行它,在这种情况下,您不必费心将它包装在 Future 中。

In Dart, though, it works slightly differently. Because slowFunction is not an async function and doesn't await anything, Dart will attempt to run it synchronously anyway, in which case you needn't have bothered wrapping it in a Future in the first place.

如果要中断同步功能的操作,则有两个选择。您必须将其分解为不同的操作,您可以在等待之间进行操作(这本身是一个复杂的过程,并不总是可能的,并且通常是代码气味),或者您使用 parallelism 而不是仅仅使用 concurrency 将功能转移到单独的线程中。

You have two options here if you want to break up the operation of your synchronous function. Either you have to break it up into distinct operations that you can await between (which is itself a somewhat complicated process, isn't always possible, and is generally a good source of code smell), or you offload the function to a separate thread altogether, employing parallelism rather than mere concurrency.

Dart是单线程的,但是可以通过使用隔离符对其进行多进程处理。 (隔离是Dart子进程的名称,与您在Dart中可以获得的真正多线程非常接近。)通过将函数包装在 Isolate 中,您可以运行在完全独立的过程中工作。这样,如果该过程阻塞2-3秒,则根本不会影响您的应用程序的大部分。

Dart is single-threaded, but it can be multi-processed through the use of isolates. (An isolate is Dart's name for a child process and is as close to true multithreading that you can get in Dart.) By wrapping your function in an Isolate, you can run the work on an entirely separate process. That way, if that process blocks for 2-3 seconds, it won't affect the bulk of your app at all.

不过有一个陷阱。由于隔离是完全不同的过程,因此不会共享任何内存。这意味着隔离区可以访问的任何数据都必须通过使用端口手动传递,即 SendPort ReceivePort 。这自然会使隔离编程有些痛苦,但是作为交换,您不会遇到诸如程序出现竞争状况或陷入僵局的情况。 (至少由于共享内存问题。严格来说,还有很多其他方法可以获取死锁和竞争条件。)

There is a catch, though. Because isolates are completely different processes, there is no sharing of memory whatsoever. That means any data that the isolate has access to has to be manually passed in through the use of "ports", namely SendPort and ReceivePort. This naturally makes isolate programming a bit of a pain, but in exchange, you won't run into things like your program having race conditions or getting deadlocked. (Because of shared memory problems, at least. Strictly speaking, there are plenty of other ways to get deadlocks and race conditions.)

使用隔离的工作方式如下:

// main process

void createIsolate() async {
  ReceivePort isolateToMain = ReceivePort();

  isolateToMain.listen((data) {
    // Listen for data passed back to the main process
  });

  Isolate myIsolateInstance = await Isolate.spawn(myIsolate, isolateToMain.sendPort);
}

// isolate process

void myIsolate(SendPort mainToIsolate) {
  final result = slowFunction();
  mainToIsolate.send(result);
}

这篇关于Dart-使长时间运行的同步功能异步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆