<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Concurrency on RawCull</title><link>https://rawcull.netlify.app/tags/concurrency/</link><description>Recent content in Concurrency on RawCull</description><generator>Hugo</generator><language>en</language><lastBuildDate>Fri, 27 Mar 2026 09:26:38 +0100</lastBuildDate><atom:link href="https://rawcull.netlify.app/tags/concurrency/index.xml" rel="self" type="application/rss+xml"/><item><title>Swift Concurrency in RawCull</title><link>https://rawcull.netlify.app/blog/2026/03/26/swift-concurrency-in-rawcull/</link><pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate><guid>https://rawcull.netlify.app/blog/2026/03/26/swift-concurrency-in-rawcull/</guid><description>&lt;h1 id="swift-concurrency-in-rawcull"&gt;Swift Concurrency in RawCull&lt;a class="td-heading-self-link" href="#swift-concurrency-in-rawcull" aria-label="Heading self-link"&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;A summarized document about Concurrency in RawCull.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1--why-concurrency-matters-in-rawcull"&gt;1 Why Concurrency Matters in RawCull&lt;a class="td-heading-self-link" href="#1--why-concurrency-matters-in-rawcull" aria-label="Heading self-link"&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;RawCull is a macOS photo-culling application that works with Sony A1 ARW raw files. A single RAW file from the A1 can be 50–80 MB. When you open a folder with hundreds of shots, the app must scan metadata, extract embedded JPEG previews, decode thumbnails, and manage a multi-gigabyte in-memory cache — all while keeping the UI perfectly fluid and responsive at 60 fps. Without concurrency that would be impossible.&lt;/p&gt;</description></item><item><title>Concurrency model</title><link>https://rawcull.netlify.app/blog/2026/03/17/concurrency-model/</link><pubDate>Tue, 17 Mar 2026 00:00:00 +0000</pubDate><guid>https://rawcull.netlify.app/blog/2026/03/17/concurrency-model/</guid><description>&lt;h1 id="concurrency-model--rawcull"&gt;Concurrency Model — RawCull&lt;a class="td-heading-self-link" href="#concurrency-model--rawcull" aria-label="Heading self-link"&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Files covered:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RawCull/Model/ViewModels/RawCullViewModel.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RawCull/Views/RawCullSidebarMainView/extension+RawCullView.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RawCull/Actors/ScanFiles.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RawCull/Actors/ScanAndCreateThumbnails.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RawCull/Actors/ExtractAndSaveJPGs.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RawCull/Actors/ThumbnailLoader.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RawCull/Actors/RequestThumbnail.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RawCull/Actors/SharedMemoryCache.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RawCull/Actors/DiskCacheManager.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RawCull/Actors/SaveJPGImage.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RawCull/Enum/SonyThumbnailExtractor.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RawCull/Enum/JPGSonyARWExtractor.swift&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="td-heading-self-link" href="#overview" aria-label="Heading self-link"&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;RawCull uses Swift structured concurrency (&lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;, &lt;code&gt;Task&lt;/code&gt;, &lt;code&gt;TaskGroup&lt;/code&gt;, and &lt;code&gt;actor&lt;/code&gt;) across four primary flows:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Flow&lt;/th&gt;
 &lt;th&gt;Entry point&lt;/th&gt;
 &lt;th&gt;Core actor(s)&lt;/th&gt;
 &lt;th&gt;Purpose&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Catalog scan&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;RawCullViewModel.handleSourceChange(url:)&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ScanFiles&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Scan ARW files, extract metadata, load focus points&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Thumbnail preload&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;RawCullViewModel.handleSourceChange(url:)&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ScanAndCreateThumbnails&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Bulk-populate the thumbnail cache for a selected catalog&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;JPG extraction&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;extension+RawCullView.extractAllJPGS()&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ExtractAndSaveJPGs&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Extract embedded JPEG previews and save to disk&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;On-demand thumbnails&lt;/td&gt;
 &lt;td&gt;UI grid + detail views&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ThumbnailLoader&lt;/code&gt;, &lt;code&gt;RequestThumbnail&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Rate-limited, cached per-file thumbnail retrieval&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The two long-running operations (thumbnail preload and JPG extraction) share a &lt;strong&gt;two-level task pattern&lt;/strong&gt;:&lt;/p&gt;</description></item></channel></rss>