{"id":13605317,"url":"https://github.com/CharlieTap/cachemap","last_synced_at":"2025-04-12T05:32:28.367Z","repository":{"id":203167173,"uuid":"704927457","full_name":"CharlieTap/cachemap","owner":"CharlieTap","description":"A read optimised concurrent map for Kotlin Multiplatform","archived":false,"fork":false,"pushed_at":"2024-08-03T11:50:39.000Z","size":318,"stargazers_count":73,"open_issues_count":1,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-08-03T19:37:16.039Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CharlieTap.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-10-14T14:29:31.000Z","updated_at":"2024-08-03T11:50:43.000Z","dependencies_parsed_at":"2023-10-27T23:19:27.550Z","dependency_job_id":"08fcb394-2d77-4dd6-aefa-83b29bfd1568","html_url":"https://github.com/CharlieTap/cachemap","commit_stats":null,"previous_names":["charlietap/cachemap"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CharlieTap%2Fcachemap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CharlieTap%2Fcachemap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CharlieTap%2Fcachemap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CharlieTap%2Fcachemap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CharlieTap","download_url":"https://codeload.github.com/CharlieTap/cachemap/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223497742,"owners_count":17155199,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T19:00:57.320Z","updated_at":"2024-11-07T10:30:24.088Z","avatar_url":"https://github.com/CharlieTap.png","language":"Kotlin","funding_links":[],"categories":["Kotlin","并发编程"],"sub_categories":["语音合成"],"readme":"# cachemap\n\n![badge][badge-android]\n![badge][badge-jvm]\n![badge][badge-ios]\n![badge][badge-linux]\n![badge][badge-mac]\n![badge][badge-windows]\n\n---\n\nCacheMap is single writer concurrent hashmap implementation.\n\nReads from the hashmap can proceed concurrently to writes from any thread with zero coordination necessary... No locks\nand no waits\n\nCacheMap implements `Map\u003cK,V\u003e` so can be used in place of existing map instances.\n\nCacheMap implements all of MutableMap\u003cK,V\u003e with the exception of `val entries: Set\u003cMap.MutableEntry\u003cK, V\u003e\u003e`\nas exposing MutableEntry's would allow mutation without the necessary write coordination.\n\nCacheMap is ultimately a thin wrapper around the [left-right concurrency primitive](#leftright).\n\n# Setup\n\n```kotlin\ndependencies {\n    implementation(\"io.github.charlietap:cachemap:0.2.4\")\n    // Or\n    implementation(\"io.github.charlietap:cachemap-suspend:0.2.4\")\n}\n```\n\n# Usage\n\nInstance creation follows the typical Kotlin convention\n\n```kotlin\nval cachemap = cacheMapOf()\n```\n\nFor sizing the initial capacity you can use\n```kotlin\nval cachemap = cacheMapOf(9000)\n```\nAnd for pre-population a varargs constructor exists\n```kotlin\nval cachemap = cacheMapOf(key to value,...)\n```\nUse cachemap like any MutableMap in Kotlin\n```kotlin\ncachemap[key] = value\n// or\ncachemap.put(key, value)\n```\n\n### Coroutines\n\nFor reasons [documented in leftright](#coroutines-1) cachemap may block or yield within methods that\nmutate the map. If you would prefer to not block the underlying thread you can use the suspending variant\nof cachemap:\n\n```kotlin\nval cachemap = suspendCacheMapOf()\n```\nUse cachemap like any MutableMap in Kotlin\n```kotlin\nscope.launch {\n    cachemap.put(key, value)\n}\n\n// Unfortunately operator functions cannot suspend so this is not possible\n// scope.launch {\n//     cachemap[key] = value\n// }\n```\n\n# leftright\n\nleft-right is a concurrency primitive which allows lock-free/wait-free reads of any mutable datastructure.\n\nConceptually left-right can be understood as a concurrency primitive that maintains two copies of a datastructure with a pointer (switch)\ndirecting traffic for reads and writes in separate directions.\n\n```mermaid\ngraph TD;\n Switch--reads--\u003eLeft;\n Switch--writes--\u003eRight;\n```\n\nIf you're interested in learning more about the intricacies of the algorithm I would recommend an [incredible video from John Gjengset](https://youtu.be/eLNAMEoKAAc?si=OwLcy5kWJRFxCHtH)\nwhich details his creation of an eventually-consistent implementation of a left-right.\nMy implementation borrows the same epoch counter algorithm for waiting on departing readers with a deviation to avoid the global epoch array lock\nby imposing a max parallelism invariant and leveraging ThreadLocal state.\n\nYou can also find what I believe to be the first paper on the primitive [here](https://hal.science/hal-01207881/document).\n\n# Setup\n\n```kotlin\ndependencies {\n    implementation(\"io.github.charlietap:leftright:0.2.4\")\n    // Or\n    implementation(\"io.github.charlietap:leftright-suspend:0.2.4\")\n}\n```\n\n# Usage\n\nLeftRight is generic over any given datastructure and can be constructed like so\n\n```kotlin\nval leftright  = LeftRight\u003cT\u003e(::constructorForT)\n\n// For example\n\nval leftRightSet = LeftRight\u003cMutableSet\u003cString\u003e\u003e(::mutableSetOf)\n```\n\n### Coroutines\n\nWhilst reads avoid locks and waits, writes are not so lucky. A write is capable of both\nblocking on a mutex and yielding back to the scheduler if readers take too long to depart.\nRather than blocking valuable thread resources you can yield back to the coroutines runtime\nusing with the suspend variant:\n\n```kotlin\nval leftright  = SuspendLeftRight\u003cT\u003e(::constructorForT)\n\n// For example\n\nval leftRightSet = SuspendLeftRight\u003cMutableSet\u003cString\u003e\u003e(::mutableSetOf)\n\n// mutate is now suspending\nscope.launch {\n    leftRightSet.mutate {\n        it.add(\"Hello worlds\")\n    }\n}\n```\n\n## Additional Reading\n\n- [Making my concurrent algo 6000% better](https://dev.to/charlietap/making-my-concurrent-algorithm-6000-better-24oo)\n\n\n## License\n\nThis project is dual-licensed under both the MIT and Apache 2.0 licenses. You can choose which one you want to use the software under.\n\n- For details on the MIT license, please see the [LICENSE-MIT](LICENSE-MIT) file.\n- For details on the Apache 2.0 license, please see the [LICENSE-APACHE](LICENSE-APACHE) file.\n\n[badge-android]: http://img.shields.io/badge/-android-6EDB8D.svg?style=flat\n[badge-jvm]: http://img.shields.io/badge/-jvm-DB413D.svg?style=flat\n[badge-linux]: http://img.shields.io/badge/-linux-2D3F6C.svg?style=flat\n[badge-ios]: http://img.shields.io/badge/-ios-CDCDCD.svg?style=flat\n[badge-mac]: http://img.shields.io/badge/-macos-111111.svg?style=flat\n[badge-windows]: http://img.shields.io/badge/-windows-4D76CD.svg?style=flat\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCharlieTap%2Fcachemap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FCharlieTap%2Fcachemap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCharlieTap%2Fcachemap/lists"}