Created
September 18, 2024 20:20
-
-
Save robertmryan/eb0771e5c96e1d36356f1cf0a49fe256 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @propertyWrapper | |
| struct Synchronized<T>: @unchecked Sendable { | |
| private var _wrappedValue: T | |
| private let lock = NSLock() | |
| var wrappedValue: T { | |
| get { lock.withLock { _wrappedValue } } | |
| set { lock.withLock { _wrappedValue = newValue } } | |
| } | |
| init(wrappedValue: T) { | |
| _wrappedValue = wrappedValue | |
| } | |
| } | |
| final class ComplexData: @unchecked Sendable { | |
| @Synchronized var firstName: String | |
| @Synchronized var lastName: String | |
| init(firstName: String, lastName: String) { | |
| self.firstName = firstName | |
| self.lastName = lastName | |
| } | |
| } | |
| actor Foo { | |
| func process1(lotsOfData: [ComplexData]) async { | |
| await withTaskGroup(of: Void.self) { group in | |
| for data in lotsOfData { | |
| group.addTask { | |
| // Do complex things with complex data, and then give data to another process | |
| await self.process2(data: data) | |
| // I will never ever do anything more with data | |
| } | |
| } | |
| } | |
| } | |
| nonisolated func process2(data: ComplexData) async { | |
| // Do complex things with complex data, and then give data to another process | |
| await process3(data: data) | |
| // I will never ever do anything more with data | |
| } | |
| nonisolated func process3(data: ComplexData) async { | |
| // Do complex things with complex data, and I am done | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you again so much for your time and advices.
The algorithm we are using is not doing any blocking calls. It is indeed looping through a vast number of elements (millions) (these millions constitutes one of the complexData, and there is also meta-data inside) and applies some maths to each of the elements and to groups of them. There are 3 passes with three different types of formulaes applied to both the original complexData plus the outcome of the previous passes.
We can have a list of thousands of complexData to process per day.
But all in all, I am not really after cancellation. I admit it may be an interesting added feature, but for that's not my goal right now. I had to struggle to convince to move from the old C version to Swift, and we did get loads of benefit from that (including removing dormant bugs). I am now just trying to move it to Swift 6 to see if we could get further benefit, but not directly looking for improvement of performance/features - at least right now. I was surprised that I didn't get so many warnings errors while switching to Swift 6.
But OK, I do get the point that structured concurrency will allow me to introduce some cancellation in the future.
I have been reading a lot about isolation context, and I now think I understand better what they are. Admittedly, 'complexData-N' does not need to move from one isolation context to another. We just need to make sure that complexData_N and complexData_N+1 are processed in parrallel (said differently, as soon as a core becomes free, we need it to start process a complexData. I guess that's exactly what
does.
I am still wondering how a non Sendable data could be moved from one isolation context to another if we promise the sending context will forever forget about that data. Maybe still old-way thinking... but I guess there might be use cases.
Once again, thank you very much.