【问题标题】:Using parallel Threads for different network operations [closed]将并行线程用于不同的网络操作[关闭]
【发布时间】:2014-07-26 04:58:22
【问题描述】:

我正在编写一个应用程序,它应该首先一个接一个地运行 2 个方法,每个方法需要 2 秒来获取第一个 tokenId,然后运行 ​​3-5 次调用不同的 Web 服务来获取数据。每次调用web service 需要 5 秒,所以我不想在一个接一个地运行它们时等待 20 秒。

获取连接然后获取令牌:

connect() 得到结果后,运行getToken ()

之后我需要显示从 3-5 web services 获得的数据,所以我想并行执行以节省一些时间。我不想等待每个完成然后运行下一个,所以我可能需要使用 3-5 个并行 Threads 来完成,然后每个 Thread 将数据保存到可共享的地方,毕竟完成在 UI 上显示数据。

一些问题:

1- 要实现connect() 和之后的getToken(),我应该为connect() 运行AsyncTask,然后在onPostExecute() 中为getToken() 启动一个新的AsyncTask,结果来自connect()

2- 因为我在每个网络服务中的所有工作都是发送数据并等待它的到来- 当每个人都调用不同的 web service 并获得结果时创建 3-4 Theards 是否正确-之后将其保存到全局位置,然后才显示它?如何实现这样的事情?

【问题讨论】:

    标签: java android multithreading android-asynctask parallel-processing


    【解决方案1】:

    是的,您可以运行多达 128 个异步任务,这是在 android 中同时运行异步任务的线程池容量。阅读下面的说明或直接从 github 下载示例。

    AsyncTask 使用线程池模式来运行来自 doInBackground() 的内容。问题最初是(在早期的 Android 操作系统版本中)池大小仅为 1,这意味着一堆 AsyncTask 没有并行计算。但后来他们修复了这个问题,现在大小为 5,所以最多 5 个 AsyncTask 可以同时运行。不幸的是,我不记得他们在哪个版本中改变了这一点。

    这是当前 (2012-01-27) API 对此的说明:

    首次引入时,AsyncTask 是在单个后台线程上串行执行的。从 DONUT 开始,这被更改为允许多个任务并行运行的线程池。在 HONEYCOMB 之后,计划将其改回单线程,以避免并行执行导致的常见应用程序错误。如果你真的想要并行执行,你可以使用这个方法的 executeOnExecutor(Executor, Params...) 版本和 THREAD_POOL_EXECUTOR;但是,请参阅那里的评论以获取有关其使用的警告。

    DONUT 是 Android 1.6,HONEYCOMB 是 Android 3.0。

    事实证明,对于使用“允许多个任务并行运行的线程池”的 API(从 1.6 开始,到 3.0 结束),同时运行的 AsyncTask 的数量取决于传递执行的任务的数量已经,但还没有完成他们的 doInBackground()。

    这是我在 2.2 上测试/确认的。假设您有一个自定义 AsyncTask,它只在 doInBackground() 中休眠一秒钟。 AsyncTask 在内部使用固定大小的队列来存储延迟任务。队列大小默认为 10。如果您连续启动 15 个自定义任务,那么前 5 个将进入它们的 doInBackground(),但其余的将在队列中等待空闲的工作线程。只要前 5 个任务中的任何一个完成,从而释放一个工作线程,队列中的一个任务就会开始执行。所以在这种情况下,最多 5 个任务将同时运行。但是,如果您连续启动 16 个自定义任务,那么前 5 个将进入它们的 doInBackground(),其余 10 个将进入队列,但是对于第 16 个,将创建一个新的工作线程,因此它将立即开始执行。所以在这种情况下,最多 6 个任务会同时运行。

    可以同时运行多少个任务是有限制的。由于 AsyncTask 使用的线程池执行器具有有限的最大工作线程数 (128),并且延迟任务队列的大小固定为 10,因此如果您尝试执行超过 138 个自定义任务,则应用程序将因 java.util.concurrent.RejectedExecutionException 而崩溃.

    从 3.0 开始,API 允许通过 AsyncTask.executeOnExecutor(Executor exec, Params... params) 方法使用您的自定义线程池执行器。例如,如果您不需要默认 10,则可以配置延迟任务队列的大小。

    这是一个简单的测试应用,用于处理任务数量、串行与并行执行:https://github.com/vitkhudenko/test_asynctas

    【讨论】:

    • 所以对于我的第一个问题,您说我可以毫无问题地致电onPostExecute 中的getToken()...O.K.关于多线程和网络的第二个问题呢,您是否建议在AsyncTask 中吃午饭,即使UI 应该在所有这些都完成后才能编辑
    • 是的,您应该创建一个网络客户端,并在每个异步中创建该类的单独实例并调用网络代码来完成您想要的工作。如果您需要更多帮助,我没有这么多次让我知道
    • 你的 ui 线程也不会被阻塞。您需要做的就是 new asynctask().executeonexecutor(asynctask.thread_pool_executor, params)
    • 网络客户端? 100% 不明白,你能在你的答案中显示代码示例吗?使用ThreadPoolExecutor 控制所有正在运行的线程不是更好吗?
    • 这是一种标准方法,因为您不负责线程池 android 自己在 kts 上执行它并自行管理它。 Webclient 指的是你的网络代码
    【解决方案2】:

    您可以探索将 CountDownlatch 与未来一起使用的可能性。获得令牌后,使用实现 Callable 的工作类实例化线程。并且在每个进程 countDown 完成后,调用闩锁上的 await 以便能够等待所有线程完成。完成后,您可以调用 Future 上的 get 方法,这将允许您访问结果,而不是将结果存储在 common/gobal 变量中。

    【讨论】:

    • 我读到使用CountDownLatchUI thread,需要等待一个或多个线程完成,然后才能开始处理。当所有线程午餐数据时,它不是阻塞UI thread 吗?为网络工作运行并行 5 个线程是否正确?
    猜你喜欢
    • 1970-01-01
    • 2018-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多