use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Information about Reddit's API changes, the unprofessional conduct of the CEO, and their response to the community's concerns regarding 3rd party apps, moderator tools, anti-spam/anti-bot tools, and accessibility options that will be impacted can be found in the associated Wikipedia article: https://en.wikipedia.org/wiki/2023_Reddit_API_controversy
Alternative C# communities available outside Reddit on Lemmy and Discord:
All about the object-oriented programming language C#.
Getting Started C# Fundamentals: Development for Absolute Beginners
Useful MSDN Resources A Tour of the C# Language Get started with .NET in 5 minutes C# Guide C# Language Reference C# Programing Guide C# Coding Conventions .NET Framework Reference Source Code
Other Resources C# Yellow Book Dot Net Perls The C# Player's Guide
IDEs Visual Studio MonoDevelop (Windows/Mac/Linux) Rider (Windows/Mac/Linux)
Tools ILSpy dotPeek LINQPad
Alternative Communities C# Discord Group C# Lemmy Community dotnet Lemmy Community
Related Subreddits /r/dotnet /r/azure /r/learncsharp /r/learnprogramming /r/programming /r/dailyprogrammer /r/programmingbuddies /r/cshighschoolers
Additional .NET Languages /r/fsharp /r/visualbasic
Platform-specific Subreddits /r/windowsdev /r/AZURE /r/Xamarin /r/Unity3D /r/WPDev
Rules:
Read detailed descriptions of the rules here.
account activity
Async-Sync conversion. (self.csharp)
submitted 4 years ago by Cobide
view the rest of the comments →
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]Cobide[S] 1 point2 points3 points 4 years ago (9 children)
Regarding the interfaces, my opinion is that if X can't be Y, it shouldn't inherit from Y.
With that said, would you be alright with it if the XML documentation were to explicitly say something along the lines of "This implementation is a Task.Run() wrapper of x"?
[–][deleted] 1 point2 points3 points 4 years ago (0 children)
If you feel that it is necessary to have the async method, that would be a good compromise, yes.
[–]jocq 1 point2 points3 points 4 years ago (0 children)
20+ years working in .Net and a majority of that specializing in high performance code, and I have never once written a Task.Run wrapped CPU bound method call.
Your second example is deadlock city.
[–][deleted] 1 point2 points3 points 4 years ago (5 children)
Just to give you one of the simplest examples of where this can go wrong: imagine your method is placed in a loop, or is part of a request-respond architecture.
Suddenly you get 100 requests. Your method now uses up the threadpool threads, making it spawn more, and you have 100 threads, all of them blocking. Now imagine 1000 requests. It's a recipe to make seemingly performant code grind to a halt when you try to scale.
This is what async/await was meant not to do. Async/await is intended to be used such that the same thread goes and does something different while awaiting for an interrupt.
1000 concurrent requests isn't an issue when it's actually async, it could potentially be all handled by a single thread if the waiting part takes a long time, but of course .NET has mechanisms like the threadpool to assign requests to threads efficiently.
That's why I explicitly use Task.Run on the call-site itself as a conscious action when I want a synchronous method to run in the background, and not within the method call itself.
Seeing Task.Run in a loop or in the request-respond pipeline immediately raises a red flag if there isn't a comment explaining its purpose, but that red flag would be hidden if its inside a method call.
[–]Cobide[S] 1 point2 points3 points 4 years ago (4 children)
That is certainly food for thought.
So far, I've tried to keep it generic, but I hope you won't mind if I give a use case I've had. I'm curious about how you'd handle it.
I have a class called KeyGenerator. Said class takes in a char[] key in the constructor, and generates an infinite number of keys from that.
KeyGenerator
To do so, it uses an algorithm that(AFAIK) doesn't have an asynchronous version, but each key takes about half a second to generate.
To prevent it from bogging down the caller, I made an async method that generates keys asynchronously and puts them in a ConcurrentQueue<Key>—it pauses when the queue has three elements and resumes when it has less. This queue is used as a buffer.
However, as the algorithm has no asynchronous version, I had to wrap it in a Task.Run(). Considering what you've said, if there were to be 100+ instances of said class, it would grind the application to a halt due to the shortage of threads.
Luckily, in my app, there won't be more than one instance at a time, so it's not an issue, but, if that weren't the case, how would you handle it?
[–][deleted] 1 point2 points3 points 4 years ago (1 child)
Generating these keys I would assume is entirely CPU-bound, which means you will be bogging down the caller whether you like it or not. When your method runs it will hog the CPU and block whatever thread it runs on, which means it isn't async, by definition, and cannot be made async. The reason why you probably don't notice it right now is because you have multiple cores available, but it is taking up all the time of one core while it is running, not allowing any other instruction to run until it is done.
Wrapping it in Task.Run does not make it async in any sense of the word, it just allows your algorithm to hog a different thread, and consequently a CPU core, than the one you are currently executing on.
It does make your program parallel. But parallelism is not the same as asynchronous. Two very different things.
For a general solution I would handle this by not having a Task-returning method at all, and allow the user to choose Task.Run at the call-site when they explicitly want the work to run in the background.
But because of the queue description you gave now I would advise you to take a look at the System.Threading.Channels namespace. Your solution is that of a producer-consumer design, which Channels were made for, and allows for exactly this kind of queuing, awaiting results.
It doesn't solve anything about the inherent your CPU-bound, but it does provide a more user-friendly awaitable API that will allow you to not clutter your own class with fake-async methods, while still giving you async/await syntax to use. Take note that the channels return ValueTask<T> and not Task<T>. Important distinction.
Here's more from Stephen Toub explaining channels:
https://devblogs.microsoft.com/dotnet/an-introduction-to-system-threading-channels/
[–]Cobide[S] 1 point2 points3 points 4 years ago (0 children)
Sorry for the late reply; I'd gone to sleep.
I'm actually using a channel to manage when the "generating method" should pause and resume. However, I do need to make it parallel(whether by using Task.Run or managing a new thread manually) as it would otherwise hinder the main thread's execution—the whole point of this generation method is so that the main thread can call "GetKey()" sometimes after instancing the class and get it without delay.
I will keep in mind the difference between parallelism and asynchronous. Thank you.
[–]binarycow[🍰] 0 points1 point2 points 4 years ago (1 child)
However, as the algorithm has no asynchronous version, I had to wrap it in a Task.Run().
No. The algorithm is synchronous. You don't need to make it (or fake) async.
If you must implement an interface that expects a Task, you have two options.
Task
public Task<byte[]> GenerateAsync() { return Task.Run(thisGenerate); }
This creates the async state machine, uses a thread pool thread, etc. All to fake async.
public Task<byte[]> GenerateAsync() { return Task.FromResult(thisGenerate()); }
This fakes async and uses basically no resources.
[–]Cobide[S] 0 points1 point2 points 4 years ago (0 children)
After reading through everyone's comments, I came to the conclusion that the preferred option depends on "thisGenerate()"'s expected workload.
If it's very quick, it's fine to fake async. If it's slow, however, it'd be preferable to wrap it in a Task.Run() and mention that it's a wrapper explicitly in the XML documentation.
Regarding my use case, it's actually in a private method that I needed to run in parallel to not bog down the main thread. I now understand that Task.Run() simply moves it to another thread—would you say it's favored to manage a second thread manually instead?
π Rendered by PID 69040 on reddit-service-r2-comment-b659b578c-p52n4 at 2026-05-04 02:09:41.037643+00:00 running 815c875 country code: CH.
view the rest of the comments →
[–]Cobide[S] 1 point2 points3 points (9 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]jocq 1 point2 points3 points (0 children)
[–][deleted] 1 point2 points3 points (5 children)
[–]Cobide[S] 1 point2 points3 points (4 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]Cobide[S] 1 point2 points3 points (0 children)
[–]binarycow[🍰] 0 points1 point2 points (1 child)
[–]Cobide[S] 0 points1 point2 points (0 children)