Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
smarion2
Apr 22, 2010
How do you guys feel about certifications? I've been looking to take my coding skills to the next level and thought about taking some c# certs to get the mcsd.

Would you say it's worth doing? My background is I majored in a basic IT degree but ended up wanting to become a programmer who majored in computer science.

Adbot
ADBOT LOVES YOU

ljw1004
Jan 18, 2005

rum

GameCube posted:

Hello. Here is a snippet of a unit test that is not doing what I want it to do...

GameCube/Inverness, sorry in advance that I'm listing so many potential issues with the codes you posted. A few things looked fishy and I wanted to run through them exhaustively. This stuff has a lot of gotchas!



You've called this variable "actionGenerator". I guess it's clear in your mind that you want a "generator" where you give it lomarf/index/delay, and it gives you back a delegate that embodies some async work which can be started at a later point in time, and can even be started an arbitrary number of times.

code:
Func<LomarfType, int, int, Action> actionGenerator = (lomarf, index, delay) => async () => {...}

// call it like this:
Action asyncAction1 = actionGenerator(marf1, 1, 10);
Action asyncAction2 = actionGenerator(marfX, 10, 1000);
asyncAction1(); // kicks off a piece of async work in a fire-and-forget manner
asyncAction2(); // kicks off a piece of async work in a fire-and-forget manner
Async work can be void-returning like you have here with Action (which means "I am a fire-and-forget long running async process where the caller can never know when I've finished and any exceptions that I throw will be lost in the ether"). Or it can be Task-returning, where the caller of the async work will be able to await until the work is done. For Task-returning the signature should be like this:

code:
Func<LomarfType, int, int, Func<Task>> actionGenerator = (lomarf, index, delay) => async () => {...}

// call it like this:
Func<Task> asyncAction1 = actionGenerator(marf1, 1, 10);
Func<Task> asyncAction2 = actionGenerator(marfN, 20, 1000);

await asyncAction1(); // kicks off a piece of async work and awaits until it has finished
await asyncAction2(); // kicks off a piece of async work and awaits until it has finished

await Task.WhenAll(asyncAction1(), asyncAction2()); // kick them both off and awaits until they're both finished
Inverness wrote this code instead:
code:
Func<LomarfType, int, int, Task> workGenerator = async (lomarf, index, delay) => {...}

// call it like this:
Task asyncWork1 = workGenerator(marf1, 1, 10);  // kick this off
Task asyncWork2 = workGenerator(marfX, 20, 1000);  // kick this off

await Task.WhenAll(asyncWork1, asyncWork2); // await until they're both finished
Inverness' code doesn't have the same "currying". It's no longer an action generator. When you invoke his lambda, it will kick off an async workload immediately (rather than giving back a delegate which has the power to kick off async work at a future time).



GameCube went to this code instead:
code:
Func<LomarfType, int, int, Task> workGenerator = (lomarf, index, delay) => Task.Run(async () => {...});

// call it like this:
Task asyncWork1 = workGenerator(marf1, 1, 10); // kick this off
Task asyncWork2 = workGenerator(marfX, 20, 1000); // kick this off

await Task.WhenAll(asyncWork1, asyncWork2); // await until they're both finished
GameCube, this code smells fishy to me. Like Inverness, you no longer have an action generator; instead, each time you invoke your generate function, it really does kick immediately a piece of work. But you've used Task.Run which causes the work to be performed on one of the background threads in the threadpool.

Net effect: you will have your two different pieces of work executing concurrently on different threadpool threads. How will your "queue" variable behave if two concurrent threads try to call "queue.DequeueLomarf()" on it at exactly the same time? You'll have to make sure that your queue (and all the other work you do inside the body of the lambda) is threadsafe.

I suspect that you don't need the threadpool, and you shouldn't be using it: Inverness' code is better. The only reason to use Task.Run and the threadpool is if you have CPU-bound code. You don't need it just for disk-bound or network-bound code. If you switch to Inverness' code (and if you're working in a single-threaded context like Winforms or WPF or UWP or ASP.NET) then you won't have to worry about concurrency.



code:
x => Task.Factory.StartNew(actionGenerator(lomarfs[x], x, delays[x]))

// take care when using Task.Factory.StartNew! ... this code will print "C" first.
var task1 = Task.Factory.StartNew(async () => {await Task.Delay(10); Console.WriteLine("A");});
var task2 = Task.Factory.StartNew(async () => {await Task.Delay(20); Console.WriteLine("B");});
await Task.WhenAll(task1, task2);
Console.WriteLine(C);

// Instead, always use Task.Run. This code will print "ABC" as desired:
var task1 = Task.Run(async () => {await Task.Delay(10); Console.WriteLine("A");});
var task2 = Task.Run(async () => {await Task.Delay(20); Console.WriteLine("B");});
await Task.WhenAll(task1, task2);
Console.WriteLine(C);
I wish they would deprecate Task.Factory.StartNew. There are almost no reasons to use it, and it does precisely the wrong thing when you pass it an async lambda. Look at the above examples. The problem is that Task.Factory.StartNew takes in a void-returning delegate, so the compiler converts the async lambda to a void-returning delegate, which means "fire and forget... kick off this async work but then return immediately and the caller can never know when the async lambda has finished".

(You didn't run into this problem, but I'm mentioning it for future).



code:
var tasks = Enumerable.Range(0, delays.Length).Select(x => actionGenerator(lomarfs[x], x, delays[x])).ToArray();

// option1: block my thread until all the tasks have finished:
Task.WaitAll(tasks);

// option2: yield my thread to other things until all the tasks have finished:
await Task.WhenAll(tasks);
Be careful. There are two confusingly-named methods, Task.WaitAll and Task.WhenAll. You should generally be in the "async/await" world, and use Task.WhenAll, and avoid Task.WaitAll.

If you did the blocking version Task.WaitAll and you used Inverness' solution, it would typically cause a deadlock. That's because "Task.WaitAll" blocks the thread until all the tasks have finished, and Inverness never spun up any additional threads to do the background work (via Task.Run), so they want to time-share the calling thread, but they can't if it's blocked!

In your code where you did Task.Run() on each individual workitem, you were saved this deadlock, but of course you ran into the race condition issue.

The best approach is "await Task.WhenAll(tasks)".

john donne
Apr 10, 2016

All suitors of all sorts themselves enthral;

So on his back lies this whale wantoning,

And in his gulf-like throat, sucks everything

That passeth near.
ljw, you are a terrific resource. Thanks for continuing to contribute.

jony neuemonic
Nov 13, 2009

smarion2 posted:

How do you guys feel about certifications? I've been looking to take my coding skills to the next level and thought about taking some c# certs to get the mcsd.

Would you say it's worth doing? My background is I majored in a basic IT degree but ended up wanting to become a programmer who majored in computer science.

If you're anything like me, they're worth it as a kick in the butt to properly learn things instead of just skimming docs.

I'm not sure how valuable they are as a resume booster though, because I got a .NET job before actually writing any. :v:

smarion2
Apr 22, 2010

jony neuemonic posted:

If you're anything like me, they're worth it as a kick in the butt to properly learn things instead of just skimming docs.

I'm not sure how valuable they are as a resume booster though, because I got a .NET job before actually writing any. :v:

Ok, thanks for the response. Yeah I mostly just want to learn how to do this programming thing the right way. I have a job now programming I just want to get rid of some of my bad habits I've got from trying to learn while developing. If it teaches me how to do thing the right way that's more than enough of a reason for me to pursue it.

GameCube
Nov 21, 2006

Thanks for the clarification! The two hurdles for me, having just started with C#, are keeping Tasks, Funcs, Actions, and their related syntax straight in my head, and knowing when/how Tasks are actually executed. From your reply, I might have accidentally accomplished what I was trying to do:

ljw1004 posted:

Net effect: you will have your two different pieces of work executing concurrently on different threadpool threads. How will your "queue" variable behave if two concurrent threads try to call "queue.DequeueLomarf()" on it at exactly the same time? You'll have to make sure that your queue (and all the other work you do inside the body of the lambda) is threadsafe.
This is in fact what I'm testing for :v: The queue is the class under test and is meant to guarantee (among other things) that the lomarfs are processed in order, without requiring a background thread to do all the processing. (The lomarfs are enqueued synchronously before this snippet to guarantee the order.) Usually the main thread is awaiting (with ConfigureAwait(false)) the code that calls into this, but there are a few cases where we don't await because we don't care about the return value, so we could possibly have a couple threads trying to hit the queue at the same time (I think?).

Looking at the code you suggested made me realize one more thing I don't understand yet - what actually happens when you call an async function without awaiting it? Does it get executed on a background thread? I'm coming from very multithreaded C++ projects where concurrency was a nightmare and I'm just now realizing that I might not have to worry about it at all now.

GameCube fucked around with this message at 18:24 on Jul 22, 2016

Red Mike
Jul 11, 2011

GameCube posted:

Looking at the code you suggested made me realize one more thing I don't understand yet - what actually happens when you call an async function without awaiting it? Does it get executed on a background thread? I'm coming from very multithreaded C++ projects where concurrency was a nightmare and I'm just now realizing that I might not have to worry about it at all now.

I may be misunderstanding this, however this is how I understand all this to work:

When you call an async function, a new task gets created (as if you'd called Task.Run, or similar). If the async function is an async void, then that's that, the task will run and any exceptions are lost to the ether (unless you're running a WinForms projects). If the async function is an async Task or async Task<T>, then you get a reference to the created task, which has already been started. This doesn't guarantee that it's already running, just that it's been told to start, which ties in to the next bit.

You have available a thread pool on which your code is running. This may vary depending on your project and your settings (an ASP.NET project has different behaviour to a console project, etc) but the general idea is that you have a pool of a lot of threads. You don't tend to personally tell a task where the task can run, except for one single case where you force the task to run on your current thread and nowhere else (I believe this is also default behaviour in async/await in a WinForms project?). The thread it chooses can be literally any thread that is currently available. In normal circumstances, this will be on a different thread from the caller I believe.

Now, when you don't actually await a task (an async Task that you store the reference to, but never actually await), the task will try and find any available thread to run on. Depending on the specific situation, if you do end up yielding soon enough after the task start (which includes if the calling function awaits something else, or if you return out of the function and that yields) then there's a chance the task will run on the same thread that it was created from. Mostly, you can treat it as if it's another thread entirely. I'm fairly certain you don't have to worry about garbage collection cleaning up the task you just started because it went out of scope, because the scheduler holds a reference to the task itself, so you can be sure it'll run, just not when it'll actually run, when it'll actually finish, or on what thread it'll run.

Something to make clear however, since there seems like there might be a misunderstanding, a normal (no configuration) await will yield, but won't, or rather won't necessarily, run the task on the thread that's yielded.

e: vvv nevermind, looks like I'm mostly wrong :v:

Red Mike fucked around with this message at 18:51 on Jul 22, 2016

ljw1004
Jan 18, 2005

rum

GameCube posted:

Looking at the code you suggested made me realize one more thing I don't understand yet - what actually happens when you call an async function without awaiting it? Does it get executed on a background thread? I'm coming from very multithreaded C++ projects where concurrency was a nightmare and I'm just now realizing that I might not have to worry about it at all now.

Good question, and this is the heart of async/await. I made a short five-minute video that explains the control flow (and why it doesn't use a background thread).
https://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Three-Essential-Tips-For-Async-Introduction

Let's imagine a "single threaded execution context", like when you're writing Winforms/WPF/UWP application and your code is invoked from the main UI thread. (Or an ASP.NET, more or less, slightly fudging the truth, more on that at the end).

code:
Task task;

void Button1Clicked(object sender, EventArgs e)
{
   task = FooAsync();
}

async Task FooAsync()
{
  Debug.WriteLine("A");
  await Task.Delay(10);
  Debug.WriteLine("B");
}
All UI-based apps have a dedicated UI thread which runs a message-pump, basically "while (true) {var msg = GetMessage(); DispatchMessage(msg);}". If you click the button, the UI system sticks a "button clicked" item into that queue. The UI thread will get around to picking up the message from the queue and dispatching it, in this case by invoking Button1Clicked.

Button1Clicked invokes FooAsync. It prints "A". It invokes Task.Delay(10), which returns a Task. Then it tries to *await* the task. At the first await point in an async method, it registers the remainder of this method to resume once the delay has finished, then it constructs a new "Task" object in the "not-yet-completed" state which it returns to its caller.

At the first await-point in an async method, that's when the async method constructs a Task and returns it to its caller. (technically, I should write "the first await-point of something that's not yet already completed").

This caller assigns the returned task into a variable, and then returns back to the UI thread's message-pump.

...

Later, the delay finishes. This executes a tiny callback which posts a message into the message-queue. The message basically says "please resume the async method where it left off". So, when the message-queue is next free and available to do work, the UI thread itself will resume the async method.

It's cooperative timeslicing.



=== BUT ===

What happens if you're not in a single-threaded execution context? (examples of these are: if FooAsync was invoked by a console app, or was invoked by some code that was itself running on the threadpool)?

In this case it's all the same as before. However, rather than posting the "please resume me" message to the UI's message-queue, it instead posts it to the threadpool's queue of workitems. Therefore any thread in the threadpool will feel free to resume work.



code:
int count = 0;

async Task f() { count ++; await Task.Delay(1); count++; }

async Task MainAsync()
{
    await Task.WhenAll(f(), f());
}
This code attempts to increment count four times. If MainAsync is invoked from a single-threaded execution context (e.g. the UI thread of a UI app) then it will work fine. But if it's invoked from a console app or a background thread, the two async methods will be KICKED OFF on the thread which called them, but they might RESUME after their await on different (even parallel) threads. So this code would have a race condition.



When you're writing library code which might be called from any synchronization context, you have to watch out for this. When you're just writing a UI or ASP.NET app, you can really take full advantage of the single-threaded timesharing nature where it only ever yields at "await" points. That liberates you to no longer have to use thread-safe datastructures :)


What about ASP.NET? It's morally like a single-threaded execution context in that it sequentializes the code you write on the ASP.NET handler thread. However, it feels free to pick up whichever thread it wants to do the next sequential slice of async work. This means that "thread-local" variables can't be relied upon from before-an-await to after-an-await. ASP.NET helps with this by automatically propagating its so-called "Execution Context" whenever it resumes async work. This execution context includes stuff like current language, current user, and variables that you store in the AsyncLocal class. So, AsyncLocal is a better choice than thread-local variables. That said, I think it's a better pattern to always pass your context explicitly in your own code rather than relying upon shared state.

ljw1004 fucked around with this message at 19:05 on Jul 22, 2016

Gul Banana
Nov 28, 2003

in yet more ljw1004 appreciation, i was helping someone with a bizarre nuget bug and found https://github.com/NuGet/Home/issues/2433 contained the exact answer we needed

Red Mike
Jul 11, 2011

ljw1004 posted:


When you're writing library code which might be called from any synchronization context, you have to watch out for this. When you're just writing a UI or ASP.NET app, you can really take full advantage of the single-threaded timesharing nature where it only ever yields at "await" points. That liberates you to no longer have to use thread-safe datastructures :)

This entire post was illuminating, and I have a question about this bit. I was under the impression that ASP.NET doesn't work in that way and that independent requests started running concurrently on independent threads, so thread-safe data structures would still be needed. Is this the 'slightly fudging the truth' bit? If so, can you go into a bit of detail on this? A lot of my work is on ASP.NET apps, and we take the multi-threaded nature of it as one of the first principles we use to design our code.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

ljw1004 posted:

At the first await-point in an async method, that's when the async method constructs a Task and returns it to its caller. (technically, I should write "the first await-point of something that's not yet already completed").

It might also be helpful to look at this via code. This method:

C# code:
async Task FooAsync()
{
  Debug.WriteLine("A");
  await Task.Delay(10);
  Debug.WriteLine("B");
}
is kind of like this:

C# code:
Task FooAsync()
{
  Debug.WriteLine("A");
  return Task.Delay(10).ContinueWith(task =>
  {
    Debug.WriteLine("B");
  });
}
It's not exactly that because async/await is way more complicated, but it's a useful mental model.

ljw1004 posted:

When you're writing library code which might be called from any synchronization context, you have to watch out for this. When you're just writing a UI or ASP.NET app, you can really take full advantage of the single-threaded timesharing nature where it only ever yields at "await" points. That liberates you to no longer have to use thread-safe datastructures :)

An important point of clarification is that ASP.NET is multi-threaded by default with regards to incoming HTTP requests, so you still have to be careful with thread-safety if something long-lived is accessed by multiple requests.

Bognar fucked around with this message at 19:15 on Jul 22, 2016

ljw1004
Jan 18, 2005

rum

Red Mike posted:

This entire post was illuminating, and I have a question about this bit. I was under the impression that ASP.NET doesn't work in that way and that independent requests started running concurrently on independent threads, so thread-safe data structures would still be needed. Is this the 'slightly fudging the truth' bit? If so, can you go into a bit of detail on this? A lot of my work is on ASP.NET apps, and we take the multi-threaded nature of it as one of the first principles we use to design our code.

I should caution that I'm not an ASP.NET expert, and if I make mistakes here then I hope someone will correct me...

code:
public class TestController : ApiController
{
    int count = 0;

    public async Task f() { count++; await Task.Delay(1); count++; }

    public async Task<HttpResponseMessage> GetMessage()
    {
        await Task.WhenAll(f(), f());
        var resp = new HttpResponseMessage(HttpStatusCode.OK);
        resp.Content = new StringContent($"{count}: {r}", System.Text.Encoding.UTF8, "text/plain");
        return resp;
    }
}
When ASP.NET receives a request to this controller, it picks a thread from its pool to handle the request. This thread first constructs an instance of the controller, and then invokes the handler method, in this case GetMessage().

This same single thread will invoke the first "f" (which increments Count and then calls Task.Delay and then returns a not-yet-completed Task). Then it will invoke the second "f" (which increments Count and then calls Task.Delay and then returns a not-yet-completed Task). Then it will call Task.WhenAll (which returns a not-yet-completed Task) and then it returns to its caller, the ASP.NET threadpool workitem who was handling this request.

Now the threadpool workitem has nothing to do, so it returns itself to the threadpool, available to handle other requests.

One millisecond later, the timer silicon in your CPU fires an interrupt, and the CPU stops what it's doing to execute an interrupt-handler, and the interrupt-handler sees that one or two delays should now be activated, so it moves them from the "sleeping event" state to the "ready event" state. This gets picked up somewhere under the hood (I don't know where) but the net effect is that there are now two instances of method "f" which are amenable to continuation.

ASP.NET does "sort of magic sequentialization". It asks for a thread from the threadpool (which might be different from the thread that handled the first part of this request). It restores this thread's thread-state for things like ExecutionContext (authenticated user, culture/locale, any AsyncLocal variables, ...). This thread does work to finish whichever one of the "f" methods that it chanced upon. I don't know whether at this point the thread is returned to the threadpool (where it will pick up the second "f") or whether it will just do the work of the second "f" immediately.

What's important is that ASP.NET has sequentialized the async. It won't execute the two continuations of "f" concurrently. It will only switch between them at await points.

Therefore the above code is threadsafe. It will definitely result in "count" being 4. No race conditions.



You're exactly right that independent requests start running concurrently on independent threads. But each individual request uses sequentialized async within itself. Therefore, if you have data-structures that are shared amongst multiple requests (e.g. static variables in your controller) then you must worry about pre-emptive concurrency and race conditions. But if you have per-request datastructures, then they'll only ever yield at await points, so you don't need to worry as much about concurrency-safe data structures.

(Of course, once you start using the threadpool yourself with Task.Run, then you do have to worry about concurrency-safe data structures).

Red Mike
Jul 11, 2011
I see, so it would be single-threaded (sort of) in the context of a single request, which isn't unexpected. I'm..fairly certain that's not exactly true, but it shouldn't come up as a problem too often. However this is basically irrelevant at the point at which you start using anything like a database context though, since that's generally shared across multiple requests (and thus multiple threads).

But yeah, that's mostly in line with what I thought, except for maybe individual requests behaving mostly like UI behaviour.

gariig
Dec 31, 2004
Beaten into submission by my fiance
Pillbug

smarion2 posted:

How do you guys feel about certifications? I've been looking to take my coding skills to the next level and thought about taking some c# certs to get the mcsd.

Would you say it's worth doing? My background is I majored in a basic IT degree but ended up wanting to become a programmer who majored in computer science.

I would say not it's not worth doing if you are paying for them. Even looking at resumes in Seattle for .NET jobs I hardly see MCSD and when I do I ignore them. I would grab a few good books (Pragmatic Programmer, Code Complete 2, Domain Driven-Design by Evans, Working Effectively with Legacy Code, The Art of Unit Testing, etc) and a Pluralsight subscription to level up your skills

EDIT: VVVV I totally agree

gariig fucked around with this message at 20:28 on Jul 22, 2016

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

gariig posted:

I would say not it's not worth doing if you are paying for them. Even looking at resumes in Seattle for .NET jobs I hardly see MCSD and when I do I ignore them. I would grab a few good books (Pragmatic Programmer, Code Complete 2, Domain Driven-Design by Evans, Working Effectively with Legacy Code, The Art of Unit Testing, etc) and a Pluralsight subscription to level up your skills

Here's another data point. When evaluating candidates, I put significantly more value to a simple, working, non-forked project on Github (or wherever) than I do a certification.

GameCube
Nov 21, 2006

A preemptive thank you for all that info. Now to read it.

e: Okay, read everything and watched the intro video in that series (the rest of which I'll watch when I have time, looks very helpful). In my case I'm working on a Xamarin app and I believe I must assume that Lomarfs may be processed on worker threads, so it looks like all my extra work around concurrency wasn't for naught after all. Thanks for the help!

GameCube fucked around with this message at 21:16 on Jul 22, 2016

No Safe Word
Feb 26, 2005

ljw1004 posted:

cool stuff including the Channel 9 series I watched all of

Thanks for this, it's already driving some changes in our library code at my work. One question though: what do you do in the cases where you are implementing an interface or an abstract method that is async by design because in the cases where the implementers can use async/await, doing so is very useful, but there are cases where some cannot reasonably do any truly asynchronous stuff? Obviously shoe-horning things into a Task is a big time red flag as you referenced in your 4th tip.

So, for example, we have a custom logging library that has a bunch of different targets (console, file system, Azure blob storage, etc.), so we have an asynchronous interface:

C# code:
interface ILogger
{
    Task LogMessageAsync(string message);
}
(some simplifications/omissions, of course)

For the Azure and file system loggers, there are natural Async methods we can await, but for the console one there's not:
C# code:
public Task LogMessageAsync(string message)
{
    Console.WriteLine( ... );   // nothing to await and no Console.WriteLineAsync call
}
Obviously, that method is "fine" and will compile, but we treat warnings as errors so it actually doesn't compile in our solution without suppressing the warning :v: But really, what do you do in these scenarios? Is wrapping in Task.Run so bad here?

Destroyenator
Dec 27, 2004

Don't ask me lady, I live in beer
Untested, but I think this would do it?
C# code:
public Task LogMessageAsync(string message)
{
    Console.WriteLine( ... );   // nothing to await and no Console.WriteLineAsync call
    return Task.FromResult(0);
}

No Safe Word
Feb 26, 2005

Destroyenator posted:

Untested, but I think this would do it?
C# code:
public Task LogMessageAsync(string message)
{
    Console.WriteLine( ... );   // nothing to await and no Console.WriteLineAsync call
    return Task.FromResult(0);
}

Well yeah the other (and probably better?) version would be:

C# code:
     return Task.CompletedTask;
But it's "shoe-horning" task stuff in there and the call is still actually synchronous.

Inverness
Feb 4, 2009

Fully configurable personal assistant.

No Safe Word posted:

...

Obviously, that method is "fine" and will compile, but we treat warnings as errors so it actually doesn't compile in our solution without suppressing the warning :v: But really, what do you do in these scenarios? Is wrapping in Task.Run so bad here?
Have a normal method that returns Task.CompletedTask (.NET 4.6+) or a task created with Task.FromResult():
code:
        private static readonly Task<TTarget> s_nullResultTask = Task.FromResult((TTarget) null);

        public Task<TTarget> GetTargetAsync()
        {
            TTarget target = GetTarget();

            if (target != null)
                return Task.FromResult(target);

            if (_loadInfo != null)
                return _loadInfo.Task;

            return s_nullResultTask;
        }
That being said, having an async, task-returning logging method sounds pretty horrible to me from a performance perspective.

Inverness fucked around with this message at 22:44 on Jul 22, 2016

ljw1004
Jan 18, 2005

rum

No Safe Word posted:

abstract method that is async by design because in the cases where the implementers can use async/await, doing so is very useful, but there are cases where some cannot reasonably do any truly asynchronous stuff? Obviously shoe-horning things into a Task is a big time red flag as you referenced in your 4th tip.
So, for example, we have a custom logging library that has a bunch of different targets (console, file system, Azure blob storage, etc.), so we have an asynchronous interface:

Does Console.WriteLine take a long time compared to the other stuff in your code?

For something that powers an Azure service and writes to the console: there's no point doing "await Task.Run( () => Console.WriteLine(s) )" because this would just tie up another threadpool thread rather than this one. You haven't changed total usage of the threadpool, you haven't decreased latency.

For something that's used in a UI app and writes the console: there's no point doing "await Task.Run( () => Console.WriteLine(s) )" because writing to the console is already plenty fast, and blocking while you write to the console won't feel like a block from UI responsiveness perspective.


It makes me think of CopyStreamAsync in the BCL. It has to do a "await stream.ReadAsync(buf,...)" to read the next buffer just in case the stream was a disk/network stream. But in the case of a MemoryStream, the implementation of MemoryStream.ReadAsync is merely to do the work synchronously, and return a Task.CompletedTask.


So yes, echoing the three people who posted before me, Task.CompletedTask is definitely the right way to go!

Mister Duck
Oct 10, 2006
Fuck the goose

TheBlackVegetable posted:

So, I'm going to start development soon on a windows desktop app, and I was going to use WPF. It needs to run Win7/8, WPF is still the best option, right?

WPF is not dead (I still get a paycheck!).

If you need to run on 7 and 8, WPF is still a solid bet. Know that most of the improvements to WPF are being targeted at supporting new OS features available in Win10. We are still doing bug fixes for downlevel platforms, certainly, but newer stuff is going to be slanted toward the latest and greatest. So on 7 and 8 you won't have the latest touch improvements and some of the nicer things we are trying to get done for this upcoming release (after .NET 4.6.2). In 4.6.2 you will specifically miss touch KB support and per monitor DPI support if you are not using Win10 Anniversary Edition.

Pure bug fixes and stuff are, usually, not chained to specific OSes so if there are improvements to be had, you will eventually see them. Sometimes there are changes needed on both the OS and the .NET side. In these circumstances you're not likely to see support on down level platforms.

Depending on how complicated your app is and what sort of features you need, none of this may matter to you in the slightest. It's hard to tell.

As a general update, still working on getting something out about what we're currently up to. Vacations and sick time have been blocking a few things. I'm waiting on permissions to merge my touch KB notification code to master in the github WPF_Samples repo . Probably this week sometime everyone can get it and try it out.

I said before that I was modernizing the touch stack and that is going fairly well. Just a couple of things to iron out with sort of hidden features WISP used to provide that I have to track down and re-implement. I'm aiming for full backward compat, but it's likely that something will be missed and random dev X will yell about something not working anymore. C'est la vie.

InevitableCheese
Jul 10, 2015

quite a pickle you've got there
Is this the right place for help with a .NET error I can't figure out? Beginner BS.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

InevitableCheese posted:

Is this the right place for help with a .NET error I can't figure out? Beginner BS.

Yes, of course.

InevitableCheese
Jul 10, 2015

quite a pickle you've got there
Well, I've been having issues with this error since this morning. I'm doing a Pluralsight tutorial, and just trying to activate MVC in my project. Tried messing around with dependencies and such and can't seem to figure it out.

code:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.TypeLoadException: Could not load type
'Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionExtensions' from assembly 'Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
   at Microsoft.Extensions.DependencyInjection.MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection services)
   at Microsoft.Extensions.DependencyInjection.MvcServiceCollectionExtensions.AddMvc(IServiceCollection services)
   at TheWorld.Startup.ConfigureServices(IServiceCollection services) in C:\Pluralsight Tutorials\ASP.NET App with MVC etc\TheWorld\src\TheWorld\Startup.cs:line 19
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.AspNetCore.Hosting.Internal.ConfigureServicesBuilder.Invoke(Object instance, IServiceCollection exportServices)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
Here's a link to the code and such in the MVC thread I made:

https://forums.asp.net/t/2099892.aspx?System+TypeLoadException+using+services+AddMvc+

EDIT: I was able to resolve this issue by changing the "Microsoft.AspNetCore.Mvc": from "1.0.0-rc2-final" to "1.1.0-alpha1-21697",

InevitableCheese fucked around with this message at 11:12 on Jul 25, 2016

Portland Sucks
Dec 21, 2004
༼ つ ◕_◕ ༽つ
I'm a 3rd year CS student working at a summer internship and my boss has recently tasked me with refactoring an old and really poorly designed winforms application to be usable on a bunch of Surfaces they ordered and it must be ~touchscreen friendly~. This whole UI development thing is entirely out of my scope so I've just been spending 8 hours a day doing research at work for the last two weeks. I'm the only CS person here, everyone else is EE's and have been just sort of hacking code together for the last decade and admittedly doing everything possible to keep all their code as simple as it can be, and I guess just now decided they might as well have a CS person on the team. What this means for me is I don't actually have any senior developers to ask for help.

I've read through Applications = Code + Markup last week and started trying to work through some pluralsight stuff on MVVM but I'm feeling like I'm not making any progress at all. I think I understand in a really basic way the basic design pattern, but I've tried implementing it myself and end up feeling like I don't know poo poo, and have tried looking at some of the frameworks (Caliburn, MVVM Light, Prism), but still feel like reading the docs or even understanding what they are supposed to do is beyond me.

I can design decent looking UI's in xaml, but when it gets down to the meat of data binding and commands nothing I do seems to work. I just got WPF Unleashed in the mail, but I feel like I'm tapped out on resources.

Keeping in mind that I just finished my junior year, is the scope of this project unreasonably complex for me to be doing by myself, or am I just totally missing something crucial that would keep this from being as difficult as it seems?

brap
Aug 23, 2004

Grimey Drawer
Just keep following tutorials and figure out why data binding doesn't work. Start with small stuff. Like bind a list to a combo box. Post some samples or something if you're really stumped. WPF isn't amazing but it's the best we got here in the real world where we have to target OSes people are still using like Windows 7 and 8.

You can certainly do it as a junior. It sucks to not have mentorship as a software intern, but this is still a good opportunity to develop some useful skills, not the least of which is the ability to teach yourself new stuff.

raminasi
Jan 25, 2005

a last drink with no ice
There's probably just some dumb simple thing you've overlooked that's making everything seem more overwhelming than it is. WPF has some serious warts, but getting toy examples up and running isn't really one of them - as suggested, just get something really basic going to make sure you're not missing anything fundamental. (And I'd stay away from frameworks to start out.)

Calidus
Oct 31, 2011

Stand back I'm going to try science!
Have you considered not porting the code to WPF and just continuing to use WinForms? I am completely clueless about your application but just setting the max form size equal to surface screen resolution-task bar size, and resizing and anchoring everything goes a long way to making something touch friendly. It is not going to win any awards but at least you will have something functional in a reasonable period of time. I have a intern this semester and one next semester and I don't think they could do what you are being asked to without significant guidance. If they did manage it, i would expect it to be a terrible mess that would be impossible to work with.

Portland Sucks
Dec 21, 2004
༼ つ ◕_◕ ༽つ
That might be an option. I was interviewed and hired on to do work on their data visualization and statistics platform and more or less ended up knocking out everything he had planned for me in about half the time he thought it would take and managed to make a lot of overall improvements on their older stuff. I think he took that performance and assumed it applied to anything he could think of and now I'm here.

I could spend the rest of the time self teaching and I'm sort of okay with that, getting paid to learn is cool, but I'm also feeling rather obligated to let him know that this seems a little over my head without anyone around to assist me in it.

The worst part is that whenever he wants to check in on how it is going the only thing he has to offer is poo poo like "it'd be nice if it auto-calibrated the screen so its easier for the floor workers" or "these boxes should probably be a little bigger" while staring at a random assortment of poo poo I just threw on the screen to work on.

edit: sorry im just bitching now

Portland Sucks fucked around with this message at 04:25 on Jul 26, 2016

rarbatrol
Apr 17, 2011

Hurt//maim//kill.

Portland Sucks posted:

That might be an option. I was interviewed and hired on to do work on their data visualization and statistics platform and more or less ended up knocking out everything he had planned for me in about half the time he thought it would take and managed to make a lot of overall improvements on their older stuff. I think he took that performance and assumed it applied to anything he could think of and now I'm here.

I could spend the rest of the time self teaching and I'm sort of okay with that, getting paid to learn is cool, but I'm also feeling rather obligated to let him know that this seems a little over my head without anyone around to assist me in it.

The worst part is that whenever he wants to check in on how it is going the only thing he has to offer is poo poo like "it'd be nice if it auto-calibrated the screen so its easier for the floor workers" or "these boxes should probably be a little bigger" while staring at a random assortment of poo poo I just threw on the screen to work on.

edit: sorry im just bitching now

These are the best possible problems you can have.

Portland Sucks
Dec 21, 2004
༼ つ ◕_◕ ༽つ

rarbatrol posted:

These are the best possible problems you can have.

Care to elaborate? I'd love to stop feeling frustrated about this.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
"I finished everything I was supposed to do way early so now I have harder things to work on" is like, the best possible outcome of an internship. You could probably spend the rest of your time there dicking around while pretending to work and still get a good recommendation out of it. I know I stressed out far more about my productivity as an intern than was actually justified, and it sounds like you may be doing the same thing. In school your assignments are tailor-made to your skill level and knowledge and failing to complete one is a bad sign, but in the work world you often have things that need to be done which no one available actually really knows how to do, so someone goes and struggles with it for a while.

Che Delilas
Nov 23, 2009
FREE TIBET WEED
Yeah, you're pretty much way ahead of the game at this point. But still, if you post some code in here people will probably be able to help you out; as another poster said it's probably some little connection you haven't wired up properly and it just takes some experience with WPF to be familiar with everything.

Portland Sucks
Dec 21, 2004
༼ つ ◕_◕ ༽つ
Thanks for the inspiration goons. I came in with a much better attitude about it today and got my MVVM pattern working. :parrot:

amotea
Mar 23, 2008
Grimey Drawer
So... I just found out binding to a list type in WPF that doesn't implement INotifyPropertyChanged causes a memory leak. I was aware of the leak caused by binding to a VM that doesn't implement INotifyPropertyChanged, but this one is new for me. I don't really recall having any issues with it in the past either (currently on .NET 4.6.1).

What do you guys do to work around this? Surely you aren't re-implementing all list types to implement INotifyPropertyChanged. That'd be insane, and nobody wants to use ObservableCollection when they don't have to. (we use only ImmutableList in our latest code)

The suggested workaround seems to be to make the Binding a OneTime Binding, but that doesn't seem to work for me.

(See here for examples: https://blog.jetbrains.com/dotnet/2014/09/04/fighting-common-wpf-memory-leaks-with-dotmemory/)

smarion2
Apr 22, 2010

gariig posted:

I would say not it's not worth doing if you are paying for them. Even looking at resumes in Seattle for .NET jobs I hardly see MCSD and when I do I ignore them. I would grab a few good books (Pragmatic Programmer, Code Complete 2, Domain Driven-Design by Evans, Working Effectively with Legacy Code, The Art of Unit Testing, etc) and a Pluralsight subscription to level up your skills

EDIT: VVVV I totally agree

Sorry late on this but thanks for the list of books. I don't really care to say I'm certified, I just want to be able to say I know what I'm doing :) I'll take a look at the books and not pay for the cert.

Inverness
Feb 4, 2009

Fully configurable personal assistant.

amotea posted:

So... I just found out binding to a list type in WPF that doesn't implement INotifyPropertyChanged causes a memory leak. I was aware of the leak caused by binding to a VM that doesn't implement INotifyPropertyChanged, but this one is new for me. I don't really recall having any issues with it in the past either (currently on .NET 4.6.1).

What do you guys do to work around this? Surely you aren't re-implementing all list types to implement INotifyPropertyChanged. That'd be insane, and nobody wants to use ObservableCollection when they don't have to. (we use only ImmutableList in our latest code)

The suggested workaround seems to be to make the Binding a OneTime Binding, but that doesn't seem to work for me.

(See here for examples: https://blog.jetbrains.com/dotnet/2014/09/04/fighting-common-wpf-memory-leaks-with-dotmemory/)
What's wrong with having your view model (assuming you use MVVM) wrap your list in a collection that does implement that interface? If not that, then do it in XAML with a behavior that does the same.

sausage king of Chicago
Jun 13, 2001
So does .net core not support SignalR at all? Someone recommended I use it in a .net core project I have, but I can't find any tutorials that actually work and all sample projects I download are broken and don't build (like this and this and this ). So I don't know if I'm just being dumb and missing something or if this just isn't possible.

Adbot
ADBOT LOVES YOU

Gul Banana
Nov 28, 2003

no, it doesn't. they're working on it for the next release of asp.net core

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply