| RFC | RFCnnnn |
|---|---|
| Author | Kirk Munro |
| Status | Draft |
| SupercededBy | |
| Version | 0.1 |
| Area | Parser |
| Comments Due | July 25, 2019 |
| Plan to implement | true |
PowerShell is getting more and more support for multi-threaded use, such as:
- the PSThreadJob module
S.M.A.PowerShell.InvokeAsyncandS.M.A.PowerShell.StopAsync- parallelization in
ForEach-Object(see related RFC 194)
With these either available now or being made available soon, it would be
helpful if scripters could easily create concurrent alternatives to arrays
(@()) and hashtables (@{}).
As a scripter,
I can easily define and work with a ConcurrentBag<PSObject>,
so that I can collect unordered objects from multiple threads in thread-safe manner.
As a scripter,
I can easily define and work with a ConcurrentDictionary<PSObject, PSObject>,
so that I can store objects relative to keys in a dictionary in thread-safe manner.
# Define a ConcurrentBag<PSObject>
$collection = ~@()
# Define a ConcurrentDictionary<PSObject,PSObject>
$dictionary = ~@{}
# Retrieve a bunch of logs from remote computers
$computers = 's1','s2','s3'
$computers | Start-ThreadJob {
# Retrieve the data and store it in a thread-safe collection
$collection += Get-LogData -ComputerName $_
# Retrieve the data and store it in a thread-safe dictionary
$dictionary[$_] = Get-LogData
}
# Process the collection as an array
$collection.ToArray()
# Process items in the dictionary
foreach ($key in $dictionary.Keys) {
# Do something with each value
$dictionary[$key]
}The data gathered in the $collection collection.
The data gathered in each key in the $dictionary collection.
- define
~@()enclosures asSystem.Collections.Concurrent.ConcurrentBag<PSObject> - define
~@{}enclosures asSystem.Collections.Concurrent.ConcurrentDictionary<PSObject,PSObject> - ensure that the
+=operator adds data to aConcurrentBag(right now using that operator withConcurrentBagresults in it being converted to an array of objects instead) - show a warning (suggestion) users if they use
[]index operators with aConcurrentBagindicating that theConcurrentBagcollection is unordered and therefore cannot be used with index operators, and suggesting that users should use the.ToArray()method ofConcurrentBagonce the collection has been populated if they want to convert it to an array and process items using their index.
There are technically two breaking changes in this RFC:
- Adding items to
ConcurrentBagwith+=results in the collection being converted into an array in current PowerShell versions. - You can create a command named
~@in PowerShell, so anyone using that command name will break if we add~@()as enclosures.
I believe both of these are low-risk breaking changes that are worth making so
that we can have easier concurrent collection support in PowerShell moving
forward. Further, the first one could be identified as a bug and is likely not
what you want, and the second one is only breaking if you happen to be invoking
your ~@ command using parentheses with at least one value inside (e.g. @(1)).
To simplify the syntax somewhat, we could implement ~() for ConcurrentBag
and ~{} for ConcurrentDictionary.
On the plus side, these are shorter and therefore easier to type. Also, by
removing the @ character from ~@(), it becomes a little less like an array
(which it is not, since arrays are ordered and you cannot index into a
ConcurrentBag, which is unordered).
On the downside, the potential for the second breaking change increases
because it is more likely that someone has created an alias of ~ than ~@.
That would only break, however, if they were invoking that command with round
brackets with at least one value inside (e.g. ~('something')), so it would
still be a very low risk breaking change.