EDIT: Whoops! I wrote this before seeing Jacobs reply to his orginal message.
Hi Jacob,
Nice to hear from new community members so enthusiastic about the langauge. It sounds like an interesting project, is work or just a hobby?
I've fixed the code so it compiles below. The basic problem was that the asynchronous workflow needs to be executed. To do this we assign it to the "workflow" idendifier then use "Async.Run".
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#light open System.IO open System.Net.Sockets open Microsoft.FSharp.Control.CommonExtensions type AsyncStream = inherit NetworkStream member stream.ReadAsyncBytesWithYield(count : int) = let buffer = Array.create count 0uy let remaining = ref count let data = seq { while(!remaining > 0) do let workflow = async { let! read = stream.ReadAsync(buffer, 0, !remaining) do remaining := !remaining - read return buffer.[0..read] } yield! Async.Run workflow } data |> Seq.to_list
I guess there could be some performance issues with this code, but I'm unwill to guess at what they might be :) It's also most always best to take the suck it and see apporach meaning testing and profiling.
Cheers,
Rob
Hi guys,
The second version of the code looks pretty strange to me: why create an Async with a single asynchronous action and then immediately run it? That's just doing a blocking read.
I think you are just after a version that used a bit less mutable state and no "while" loop. Here's one way to do this:
1 2 3 4 5 6 7 8 9 10 11 12
type System.IO.Stream with /// Will return when count number of bytes have been read member stream.ReadAsyncBytes(count : int) = let buffer = Array.create count 0uy let rec readBytes(index, remaining) = async { let! read = stream.ReadAsync(buffer, index, remaining) do! readBytes(index + read, remaining - read) } readBytes(0,count)
Here's a version that doesn't mutate arrays at all, though to be honest the above is probably better.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
type System.IO.Stream with member stream.ReadAsyncByteList(max:int) = async { let buffer = Array.create max 0uy let! read = stream.ReadAsync(buffer, 0, max) return buffer.[0..read-1] } member stream.ReadAsyncBytes(count : int) = let rec readBytes(remaining) = async { let! read = stream.ReadAsyncByteList(remaining) let! rest = readBytes(remaining - read.Length) return Array.append read rest } readBytes(count)
I also think you're trying to mix synchronous (= blocking) sequences with async programming (= non-blocking). This won't work. Fundamentally, synchronous sequences work by making blocking calls to methods and properties "Current" and "MoveNext". I believe you would need to define an "asynchronous sequence" to get a non-blocking sequence (i.e. where each "request" for data doesn't block the requesting thread but instead returns an Async computation).
I suspect the underlying types would be:
1 2 3 4 5 6 7 8 9 10 11 12
type IAsyncEnumerator<'a> = abstract Current : 'a abstract MoveNext : unit -> Async<bool> type IAsyncEnumerable<'a> = abstract GetEnumerator : unit -> IAsyncEnumerator<'a> type AsyncSeq = IAsyncEnumerable<'a>
The types of the combinators would look something like this:
1 2 3 4 5 6
AsyncSeq.map : ('a -> Async<'b>) -> AsyncSeq<'a> -> AsyncSeq<'b> AsyncSeq.iter : ('a -> Async<unit>) -> AsyncSeq<'a> -> Async<unit> etc.
You would be able to build a computation expression builder for this type. It's very similar to monadic programming in Haskell, of course.
Note the existence of both blocking and non-blocking sequences is normal for non-blocking programming: the non-blocking nature of the code inevitably gives rise to this.
Kind regards
don
Hi Robert and Don,
Thanks for the replies.
I am running a small indie game company – 3 Lives Left – with a couple of friends, so we do need to get some code running to get bread and butter on the table – and F# is such a fun way to do it.
We have been following the language on the side for a year or so. We have tried getting our feets wet with F# earlier, but starting a business and also having to learn a new language was too much. So we have been waiting for your books to become available. It makes it a lot easier to get started. Thanks! :)
Oh yes, I see that I don't win much with only one async operation in the expression now combined with Async.Run. Regarding the Async.Run call, my thought was to exchange that with something like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
member stream.Read(count : int) = let buffer = Array.create count 0uy let remaining = ref count let data = seq { let rec yieldResult result = remaining := !remaining - result.Length yield! result if(!remaining > 0) Async.Spawn(asyncComputation) and asyncComputation = async { let! read = stream.ReadAsync(buffer, 0, !remaining) do yieldResult buffer.[0..read] } Async.Spawn(asyncComputation) } data
But then I ran into a problem with yield in the yieldResult function* and recursive bindings not allowed in comprehensions. At that time it was late, and my head was too full to cope with more F#.
Looking at the idea now, I am not even sure what I expect the code to do, since spawning the async computation would just yield nothing (?). I think I got it messed up in trying to apply as much new stuff as I could.
To make sure my understanding is correct:
If the solution with only one async call had two or more async calls instead, then it would make sense with the Async.Run call, right? Since then i would get the benefit of the async computation each time I iterated over the seqence? So mixing seqence and async expressions makes sense to do like in this example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
#light open System open System.IO open Microsoft.FSharp.Control open Microsoft.FSharp.Control.CommonExtensions let data = seq { use fiskFile = File.OpenRead("C:\fisk.txt") use hestFile = File.OpenRead("C:\hest.txt") let buffer = Array.create 2 0uy for i in 0..5 do let asyncop = async { let! _ = fiskFile.ReadAsync(buffer, 0, 1) let! _ = hestFile.ReadAsync(buffer, 1, 1) return (buffer.[0], buffer.[1]) } yield Async.Run(asyncop) } let writeData() = use fiskFile = File.OpenWrite("C:\fisk.txt") use hestFile = File.OpenWrite("C:\hest.txt") let buffer = Array.create 2 0uy buffer.[0] <- 1uy buffer.[1] <- 2uy for i in 0..5 do fiskFile.Write(buffer, 0, 1) hestFile.Write(buffer, 1, 1) writeData() Seq.iter(fun x -> printfn "%A" x) data Console.ReadKey() val data : seq<byte * byte> val writeData : unit -> unit (1uy, 2uy) (1uy, 2uy) (1uy, 2uy) (1uy, 2uy) (1uy, 2uy) (1uy, 2uy)
Thanks for the code suggestions – I changed it to suit my needs to this:
1 2 3 4 5 6 7 8 9 10 11 12
type System.IO.Stream with /// Will return when count number of bytes have been read member stream.ReadAsyncBytes(count : int) = let buffer = Array.create count 0uy let rec readBytes(index, remaining) = async { let! read = stream.ReadAsync(buffer, index, remaining) match remaining - read with | 0 -> return buffer | _ -> let! res = readBytes(index + read, remaining - read) return res } readBytes(0,count)
since I want it to have the signature int -> Async<byte array> - btw I think the termination case is missing in original recursive readBytes function?
Interesting suggestion about the builder – I think I might need to get more into the language before I try, plus I need to find the time – got a game to make :)
Best regards,
Jacob
* is that because yield only makes sense inside the seq expression, and putting it into a function makes it possible to return the function to a context (the seqence) where it no longer makes sense?
Hi
A more easier to read edition
1 2 3 4 5 6 7 8 9 10
type System.IO.Stream with /// Will return when count number of bytes have been read member stream.ReadAsyncBytes(count : int) = let buffer = Array.create count 0uy let rec readBytes(index, remaining) = async { match remaining with | 0 -> return buffer | _ -> let! read = stream.ReadAsync(buffer, index, remaining) return! readBytes(index + read, remaining - read)} readBytes(0,count)
trying to understand monads I found this
Thought it might help others that, like me, don't have experience with them.
Best regards,
Jacob
I've been writing my chat server example to use workflows so it doesn't block any threads. I tried at first unsuccesfully to combine async and seq workflows, which when I found this post again. I now fully understands Don's comments about sequences being bloking. Here's my effort at server, any feedback welcome:
Hi,
been working more on my problem. My current solution looks like this now
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
member stream.ReadAsyncBytes(count : int) = async { let buffer = Array.create count 0uy let remaining = ref count let data = seq { while(!remaining > 0) do let result = async { let! read = stream.ReadAsync(buffer, 0, !remaining) do remaining := !remaining - read return buffer.[0..read] } yield! Async.Run(result) } return data |> Seq.to_array }
which actually compiles! Unfortunately it fails my unit tests, as it doesn't return data from the stream...darn (and no more time this evening)
The changes are that I have wrapped the function into an async expression and then found the yield! (yield bang) function in Robert Pickerings excellent article at [link:www.infoq.com]
I am beginning to think that solution 1 might be prettier (in the sense that its easier to understand - at least for old time C#'ers - and a bit shorter)
I have noticed that other posts have nice coloring on their code snippets - where can I find the functionality?
Best regards,
Jacob
Edit:
Come to think of it, perhaps I dont need the int -> Async<byte array> type anymore, but more like something in this direction:
1 2 3 4 5 6 7 8 9 10 11 12 13
member stream.Read(count : int) = let buffer = Array.create count 0uy let remaining = ref count let data = seq { while(!remaining > 0) do let result = async { let! read = stream.ReadAsync(buffer, 0, !remaining) do remaining := !remaining - read return buffer.[0..read] } yield! Async.Run(result) } data
hmm....
Topic tags
- f# × 3705
- websharper × 1897
- compiler × 286
- functional × 201
- ui next × 139
- c# × 121
- classes × 97
- web × 97
- .net × 84
- book × 84
- async × 76
- ui.next × 67
- bug × 54
- core × 49
- website × 49
- server × 45
- parallel × 43
- ui × 43
- enhancement × 41
- parsing × 41
- testing × 41
- trywebsharper × 41
- typescript × 37
- html × 35
- javascript × 35
- owin × 35
- asynchronous × 30
- monad × 28
- ocaml × 28
- tutorial × 27
- warp × 27
- haskell × 26
- sitelet × 25
- linq × 22
- workflows × 22
- wpf × 20
- fpish × 19
- introduction × 19
- silverlight × 19
- sitelets × 19
- monodevelop × 17
- rpc × 17
- suave × 17
- piglets × 16
- collections × 15
- feature request × 15
- jquery × 15
- templates × 15
- getting started × 14
- pipeline × 14
- kendoui × 13
- reactive × 12
- 4.1.0.171 × 11
- monads × 11
- opinion × 10
- 4.0.190.100-rc × 9
- deployment × 9
- fixed × 9
- formlets × 9
- in × 9
- json × 9
- plugin × 9
- proposal × 9
- scheme × 9
- solid × 9
- basics × 8
- concurrent × 8
- highcharts × 8
- how-to × 8
- python × 8
- 4.1.1.175 × 7
- complexity × 7
- documentation × 7
- visual studio × 7
- 4.1.2.178 × 6
- lisp × 6
- real-world × 6
- released in 4.0.192.103-rc × 6
- remoting × 6
- resources × 6
- scala × 6
- websharper ui.next × 6
- workshop × 6
- xaml × 6
- 4.0.193.110 × 5
- 4.2.3.236 × 5
- aspnetmvc × 5
- authentication × 5
- azure × 5
- bootstrap × 5
- conference × 5
- dsl × 5
- formlet × 5
- java × 5
- list × 5
- metaprogramming × 5
- ml × 5
- released in Zafir.4.0.188.91-beta10 × 5
- sql × 5
- visualstudio × 5
- websharper.forms × 5
- zafir × 5
- 4.0.192.106 × 4
- 4.0.195.127 × 4
- 4.1.0.38 × 4
- 4.2.1.86 × 4
- 4.2.6.118 × 4
- css × 4
- example × 4
- extensions × 4
- fsi × 4
- fsx × 4
- html5 × 4
- jqueryui × 4
- lift × 4
- reflection × 4
- remote × 4
- rest × 4
- spa × 4
- teaching × 4
- template × 4
- websocket × 4
- wontfix × 4
- 4.0.196.147 × 3
- 4.1.0.34 × 3
- 4.1.6.207 × 3
- 4.2.1.223-beta × 3
- 4.2.11.258 × 3
- 4.2.4.114 × 3
- 4.2.4.247 × 3
- 4.2.5.115 × 3
- 4.2.6.253 × 3
- 4.2.9.256 × 3
- ajax × 3
- alt.net × 3
- aml × 3
- asp.net mvc × 3
- canvas × 3
- cloudsharper × 3
- compilation × 3
- database × 3
- erlang × 3
- events × 3
- extension × 3
- file upload × 3
- forums × 3
- inline × 3
- issue × 3
- kendo × 3
- macro × 3
- mono × 3
- msbuild × 3
- mvc × 3
- pattern × 3
- piglet × 3
- released in Zafir.4.0.187.90-beta10 × 3
- svg × 3
- type provider × 3
- view × 3
- 4.1.1.64 × 2
- 4.1.5.203 × 2
- 4.1.7.232 × 2
- 4.2.10.257 × 2
- 4.2.3.111 × 2
- 4.2.5.249 × 2
- android × 2
- asp.net × 2
- beginner × 2
- blog × 2
- chart × 2
- client × 2
- client server app × 2
- clojure × 2
- computation expressions × 2
- constructor × 2
- corporate × 2
- courses × 2
- cufp × 2
- d3 × 2
- debugging × 2
- direct × 2
- discriminated union × 2
- docs × 2
- elm × 2
- endpoint × 2
- endpoints × 2
- enterprise × 2
- entity framework × 2
- event × 2
- f# interactive × 2
- fable × 2
- flowlet × 2
- formdata × 2
- forms × 2
- fsc × 2
- google maps × 2
- hosting × 2
- http × 2
- https × 2
- iis 8.0 × 2
- install × 2
- interactive × 2
- interface × 2
- iphone × 2
- iteratee × 2
- jobs × 2
- jquery mobile × 2
- keynote × 2
- lens × 2
- lenses × 2
- linux × 2
- listmodel × 2
- mac × 2
- numeric × 2
- oauth × 2
- obfuscation × 2
- offline × 2
- oop × 2
- osx × 2
- packaging × 2
- pattern matching × 2
- performance × 2
- pipelines × 2
- q&a × 2
- quotation × 2
- reference × 2
- released in Zafir.4.0.185.88-beta10 × 2
- rx × 2
- script × 2
- security × 2
- self host × 2
- seq × 2
- sockets × 2
- stm × 2
- tcp × 2
- trie × 2
- tutorials × 2
- type × 2
- url × 2
- var × 2
- websharper.charting × 2
- websharper4 × 2
- websockets × 2
- wig × 2
- xna × 2
- zh × 2
- .net interop × 1
- 2012 × 1
- 4.0.194.126 × 1
- 4.1.3.184 × 1
- 4.1.4.189 × 1
- 4.2.0.214-beta × 1
- 4.2.12.259 × 1
- 4.2.2.231-beta × 1
- 4.2.8.255 × 1
- Canvas Sample Example × 1
- DynamicStyle Animated Style × 1
- Fixed in 4.0.190.100-rc × 1
- Released in Zafir.UI.Next.4.0.169.79-beta10 × 1
- SvgDynamicAttribute × 1
- WebComponent × 1
- abstract class × 1
- accumulator × 1
- active pattern × 1
- actor × 1
- addin × 1
- agents × 1
- aggregation × 1
- agile × 1
- alter session × 1
- animation × 1
- anonymous object × 1
- apache × 1
- api × 1
- appcelerator × 1
- architecture × 1
- array × 1
- arrays × 1
- asp.net 4.5 × 1
- asp.net core × 1
- asp.net integration × 1
- asp.net mvc 4 × 1
- asp.net web api × 1
- aspnet × 1
- ast × 1
- attributes × 1
- authorization × 1
- b-tree × 1
- back button × 1
- badimageformatexception × 1
- bash script × 1
- batching × 1
- binding-vars × 1
- bistro × 1
- body × 1
- bundle × 1
- camtasia studio × 1
- cas protocol × 1
- charts × 1
- clarity × 1
- class × 1
- cli × 1
- clipboard × 1
- clojurescript × 1
- closures × 1
- cloud × 1
- cms × 1
- coding diacritics × 1
- color highlighting × 1
- color zones × 1
- combinator × 1
- combinators × 1
- compile × 1
- compile code on server × 1
- config × 1
- confirm × 1
- content × 1
- context × 1
- context.usersession × 1
- continuation-passing style × 1
- coords × 1
- cordova × 1
- cors × 1
- coursera × 1
- cross-domain × 1
- csla × 1
- current_schema × 1
- custom content × 1
- data × 1
- data grid × 1
- datetime × 1
- debug × 1
- declarative × 1
- delete × 1
- devexpress × 1
- dhtmlx × 1
- dictionary × 1
- directattribute × 1
- disqus × 1
- distance × 1
- do binding × 1
- doc elt ui.next upgrade × 1
- docker × 1
- dojo × 1
- dol × 1
- dom × 1
- domain × 1
- du × 1
- duf-101 × 1
- dynamic × 1
- eastern language × 1
- eclipse × 1
- edsl × 1
- em algorithm × 1
- emacs × 1
- emotion × 1
- enums × 1
- error × 1
- etw × 1
- euclidean × 1
- eventhandlerlist × 1
- examples × 1
- ext js × 1
- extension methods × 1
- extra × 1
- facet pattern × 1
- failed to translate × 1
- fake × 1
- fantomas × 1
- fear × 1
- float × 1
- form × 1
- form-data × 1
- forum × 1
- fp × 1
- frank × 1
- fsdoc × 1
- fsharp × 1
- fsharp.core × 1
- fsharp.powerpack × 1
- fsharpx × 1
- fsunit × 1
- function × 1
- functional style × 1
- game × 1
- games × 1
- gc × 1
- generic × 1
- geometry × 1
- getlastwin32error × 1
- getting-started × 1
- google × 1
- google.maps × 1
- grid × 1
- group × 1
- guide × 1
- hash × 1
- headers × 1
- hello world example × 1
- heroku × 1
- highchart × 1
- history × 1
- how to × 1
- html-templating × 1
- http405 × 1
- httpcontext × 1
- hubfs × 1
- i18n × 1
- ie 8 × 1
- if-doc × 1
- iis × 1
- image × 1
- images × 1
- inheritance × 1
- initialize × 1
- input × 1
- install "visual studio" × 1
- installer × 1
- int64 × 1
- interfaces × 1
- internet explorer × 1
- interop × 1
- interpreter × 1
- io × 1
- iobservable × 1
- ios × 1
- iot × 1
- ipad × 1
- isomorphic × 1
- javascript optimization × 1
- javascript semanticui resources × 1
- jquery-plugin × 1
- jquery-ui × 1
- jquery-ui-datepicker × 1
- js × 1
- kendo datasource × 1
- kendochart × 1
- kendoui compiler × 1
- knockout × 1
- l10n × 1
- learning × 1
- library × 1
- libs × 1
- license × 1
- licensing × 1
- lineserieszonescfg × 1
- local setting × 1
- localization × 1
- logging × 1
- loop × 1
- macros × 1
- mailboxprocessor × 1
- mapping × 1
- maps × 1
- markerclusterer × 1
- markup × 1
- marshal × 1
- math × 1
- mathjax × 1
- message × 1
- message passing × 1
- message-passing × 1
- meta × 1
- metro style × 1
- micro orm × 1
- minimum-requirements × 1
- mix × 1
- mobile installation × 1
- mod_mono × 1
- modal × 1
- module × 1
- mouseevent × 1
- mouseposition × 1
- multidimensional × 1
- multiline × 1
- multithreading × 1
- mysql × 1
- mysqlclient × 1
- nancy × 1
- native × 1
- nested × 1
- nested loops × 1
- node × 1
- nunit × 1
- object relation mapper × 1
- object-oriented × 1
- om × 1
- onboarding × 1
- onclick × 1
- optimization × 1
- option × 1
- orm × 1
- os x × 1
- output-path × 1
- override × 1
- paper × 1
- parameter × 1
- persistence × 1
- persistent data structure × 1
- phonegap × 1
- pola × 1
- post × 1
- powerpack × 1
- prefix tree × 1
- principle of least authority × 1
- privacy × 1
- private × 1
- profile × 1
- programming × 1
- project × 1
- project euler × 1
- projekt_feladat × 1
- protected × 1
- provider × 1
- proxy × 1
- ptvs × 1
- public × 1
- pure f# × 1
- purescript × 1
- qna × 1
- quant × 1
- query sitelet × 1
- question × 1
- quotations × 1
- range × 1
- raphael × 1
- razor × 1
- rc × 1
- reactjs × 1
- real-time × 1
- ref × 1
- region × 1
- released in 4.0.190.100-rc × 1
- reporting × 1
- responsive design × 1
- rest api × 1
- rest sitelet × 1
- restful × 1
- round table × 1
- router × 1
- routing × 1
- rpc reverseproxy × 1
- runtime × 1
- sales × 1
- sample × 1
- sampleapp × 1
- scriptcs × 1
- scripting × 1
- search × 1
- self hosted × 1
- semanticui × 1
- sequence × 1
- serialisation × 1
- service × 1
- session-state × 1
- sharepoint × 1
- signals × 1
- sitelet website × 1
- sitelet.protect × 1
- sitlets × 1
- slickgrid × 1
- source code × 1
- sqlentityconnection × 1
- ssl × 1
- standards × 1
- static content × 1
- stickynotes × 1
- streamreader × 1
- stress × 1
- strong name × 1
- structures × 1
- submitbutton × 1
- subscribe × 1
- svg example html5 websharper.ui.next × 1
- sweetalert × 1
- system.datetime × 1
- system.reflection.targetinvocationexception × 1
- table storage × 1
- targets × 1
- tdd × 1
- templates ui.next × 1
- templating × 1
- text parsing × 1
- three.js × 1
- time travel × 1
- tls × 1
- tooltip × 1
- tracing × 1
- tsunamiide × 1
- turkish × 1
- twitter-bootstrap × 1
- type erasure × 1
- type inference × 1
- type providers × 1
- type-providers × 1
- typeprovider × 1
- ui next forms × 1
- ui-next × 1
- ui.next jqueryui × 1
- ui.next charting × 1
- ui.next formlets × 1
- ui.next forms × 1
- ui.next suave visualstudio × 1
- ui.next templating × 1
- unicode × 1
- unittest client × 1
- upload × 1
- usersession × 1
- validation × 1
- vb × 1
- vb.net × 1
- vector × 1
- view.map × 1
- visal studio × 1
- visual f# × 1
- visual studio 11 × 1
- visual studio 2012 × 1
- visual studio shell × 1
- vs2017 compiler zafir × 1
- vsix × 1
- web api × 1
- web-scraping × 1
- webapi × 1
- webcomponents × 1
- webforms × 1
- webgl × 1
- webrtc × 1
- webshaper × 1
- websharper async × 1
- websharper codemirror × 1
- websharper f# google × 1
- websharper forms × 1
- websharper reactive × 1
- websharper rpc × 1
- websharper sitelets routing × 1
- websharper warp × 1
- websharper-interface-generator × 1
- websharper.chartsjs × 1
- websharper.com × 1
- websharper.exe × 1
- websharper.owin × 1
- websharper.ui.next × 1
- websharper.ui.next jquery × 1
- websockets iis × 1
- why-websharper × 1
- windows 7 × 1
- windows 8 × 1
- windows-phone × 1
- winrt × 1
- www.grabbitmedia.com × 1
- xamarin × 1
- xml × 1
- yeoman × 1
- yield × 1
- zafir beta × 1
- zafir websharper4 × 1
- zarovizsga × 1
![]() |
Copyright (c) 2011-2012 IntelliFactory. All rights reserved. Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy |
Built with WebSharper |
Hi,
I am working on a networked game where we expect to write the networking and core game mechanics in F# - because F# is such a fantabulous language :)
I am new to F# (I am used to coding in C#) and would like to expand my mind. I have two implementations of extension methods to the Stream class below, where 1 is a nearly direct translation from C#, and 2 is an attempt to combine sequences and async expressions - but alas I just can't get it to compile.
The code is to be used in the networking layer, where I start out waiting for a Int32 (4 bytes) that contains the length of the following byte array (the game data package) that should be read.
The implementations are:
1)
Old schoolehrm C#'ish implementation:open System.IO
2) more F#'ish implementation (?) that does not compile:
If anyone could explain/show me how to get example 2 to compile I sure would appriciate it - or, even better, have other suggestions as how to write it.
I am a bit worried that the tight while(remaining... loop defeats the purpose of doing the networking code async - or may put strains on the ThreadPool. I would have preferred to register a callback function, that was called when data is available on the network stream, but I have not been able to locate a hook.
Any comments are more than welcome
Best regards,
Jacob