如何在一秒内使用Kotlin按lastModified()和length()对144,000个文件进行排序?

huangapple go评论95阅读模式
英文:

How to sort 144,000 files by lastModified() and length() in Kotlin within a second?

问题

我有以下的 File 的 ArrayList。

var a = ArrayList<File>()
var b = ArrayList<File>()
var c = ArrayList<File>()
var d = ArrayList<File>()
var e = ArrayList<File>()

一旦应用程序启动,上述 ArrayList 将填充超过 144,000 个文件。所有这些文件的总大小将近 3.5 GB。我想按照 lastModified() 或 length() 来对它们进行排序,然后在 RecyclerView 中更新已修改的 ArrayList。

为了方便排序,我将上述的 ArrayList 转换为以下形式的 Array<ArrayList<File>>

val mList = arrayOf(a, b, c, d, e)

为了加快速度,我在后台线程中执行所有操作。代码如下:

doAsync {
    mList.forEach { index ->
        index.sortByDescending { it.lastModified() }
    }
    activityUiThread {
        setRecyclerViewAdapter() // 使用新排序的文件更新 RecyclerView
    }
}

链接到我使用的在后台线程中对文件进行排序的库:https://github.com/Kotlin/anko

上述代码需要大约 3-5 秒才能执行完毕。我希望能在一秒内完成。如何解决这个问题?我是为 Android 做这个操作的。

如果需要的话,我可以准备更改 API 以执行后台任务。

英文:

I have the following ArrayList of File.

    var a  = ArrayList&lt;File&gt;()
    var b  = ArrayList&lt;File&gt;()
    var c  = ArrayList&lt;File&gt;()
    var d  = ArrayList&lt;File&gt;()
    var e  = ArrayList&lt;File&gt;()

Once the application has started the above ArrayList will be filed with more than 144,000 files. The total size all these combined would nearly 3.5 GB. I want to sort them by lastModified() or length() within in a second and update the modified ArrayList into RecyclerView.

For ease of sorting I have made above ArrayList into a Array&lt;ArrayList&lt;File&gt;&gt; as follows :

    val mList  = arrayOf(a,b,c,d,e)

To speed up things I do everything in background thread. Code :

          doAsync {
              mList.forEach{ index -&gt;
                  index.sortByDescending { it.lastModified() }
              }
              activityUiThread {
                  setRecyclerViewAdapter() // Update RecyclerView with new sorted files
              }

          }


Link to the library I used sort files do in background thread : <https://github.com/Kotlin/anko>

The above code takes nearly 3-5 seconds to execute. I want this to be done within a second. How to solve this issue ? I am doing this for android.

If needed Im ready to change the API to do the background task

答案1

得分: 1

I want this to be done within a second

简短回答:通常情况下,这是不可能的。文件系统(无论是在Android还是其他任何操作系统上)可能会超载,因此此操作有时可能会暂停您的应用程序。请注意这一点。

但是,您可以通过使用以下算法加快代码执行速度:

  • 并行读取文件的元数据
  • 根据这些结果对文件进行排序

请使用下面的示例。请注意,它执行了大量的并行IO操作。

这种解决方案的优点包括:

  • 元数据从单独的上下文中读取(该上下文具有线程限制,以避免IO过度使用)
  • 文件X的元数据仅读取一次。
  • 排序算法仅使用操作内存,例如,它使用已准备好的数据,从而减少了IO访问。
suspend fun sortFiles(files: Iterable<File>): List<File> {
    val metadataReadTasks: List<Deferred<FileWithMetadata>> = withContext(Dispatchers.IO) {
        files.map { file ->
            async {
                FileWithMetadata(file)
            }
        }
    }
    val metadatas: List<FileWithMetadata> = metadataReadTasks.awaitAll()
    return metadatas
        .sorted()
        .map {
            it.file
        }
}

private class FileWithMetadata(
    val file: File
) : Comparable<FileWithMetadata> {
    private val lastModified = file.lastModified()
    private val length = file.length()
    override fun compareTo(other: FileWithMetadata): Int {
        return when (other.length) {
            this.length -> other.lastModified.compareTo(this.lastModified)
            else -> other.length.compareTo(this.length)
        }
    }
}
英文:

> I want this to be done within a second

Short: it is impossible in general case. File System (on Android or on any other OS) can be overloaded, so this operation can pause your application sometimes. Please note this.

However you can speedup the code by using the following algorithm:

  • Read file metadata in parallel
  • Sort files via these results.

Please use example below. Please note that it does a lot of parallel IO operations.

Benefits of this solution:

  • Metadatas are read from the separate context (which has thread limit, to avoid IO overuse)
  • Metadata of file X is read only one time.
  • Sorting algorithm works with operating memory only, e.g. it use ready data, which reduces IO access.
suspend fun sortFiles(files: Iterable&lt;File&gt;): List&lt;File&gt; {
    val metadataReadTasks: List&lt;Deferred&lt;FileWithMetadata&gt;&gt; = withContext(Dispatchers.IO) 
 {
        files.map { file -&gt;
            async {
                FileWithMetadata(file)
            }
        }
    }
    val metadatas: List&lt;FileWithMetadata&gt; = metadataReadTasks.awaitAll()
    return metadatas
        .sorted()
        .map {
            it.file
        }
}
private class FileWithMetadata(
    val file: File
) : Comparable&lt;FileWithMetadata&gt; {
    private val lastModified = file.lastModified()
    private val length = file.length()
    override fun compareTo(other: FileWithMetadata): Int {
        return when (other.length) {
            this.length -&gt; other.lastModified.compareTo(this.lastModified)
            else -&gt; other.length.compareTo(this.length)
        }
    }
}

huangapple
  • 本文由 发表于 2020年1月7日 00:15:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/59615426.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定