I have this code:
let client = listener.AcceptTcpClient()
let stream = client.GetStream()
let sr = new StreamReader(stream)
let sw = new StreamWriter(stream)
How should I close these things after I use them?
If I close client,will stream,sr,sw auto close?Or I need to close them one by one?Or should I use "use" to replace let,then I need not to close them manual?
If I want to use "use" keyword like this:
let listener=new TcpListener(IPAddress.Parse("127.0.0.1"),2000)
let private loop (client : TcpClient, sr : StreamReader, sw : StreamWriter) =
async {
sw.WriteLine("a")
}
let private startLoop () =
while true do
use client = listener.AcceptTcpClient()
use stream = client.GetStream()
use sr = new StreamReader(stream)
use sw = new StreamWriter(stream)
sw.AutoFlush <- true
Async.Start(loop (client, sr, sw))
listener.Start()
startLoop ()
When client connect,server got error:can't write to closed TextWriter
So when I use "use",the handle will dispose in startLoop function?
In this program,I need to use let,then close client,sr,sw,stream manual?
Thanks
StreamReader.Dispose closes the underlying stream, releases the unmanaged resources used by the StreamReader, and optionally releases the managed resources.
That's why theoretically it is enough to use Dispose only on StreamReader
In your first code (without async) use "use" keyword for all disposable objects even if there is single real unmanaged resource in Stream class.
There are situations when you have one raw stream and you pass it sequentially to many other methods to read peace's of stream using StremReader's.
let readPart stream =
// note there is no dispose to don't close external stream
let reader = new StreamReader(stream)
// read data and return result
use stream = File.Open()
//read first part
let data1 = readPart stream
let data2 = readPart stream
// here stream should be closed
In async code you should close streams after usage. You may open stream in infinite loop but don't dispose it there and close StreamWriter after write operation. StreamWriter will dispose will close your stream.
sw.WriteLine("a")
https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/unmanaged
Related
I'm publishing events to an Azure Event Hub with an F# script. The equivalent C# code is as follows:
var connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>";
var eventHubName = "<< NAME OF THE EVENT HUB >>";
await using (var producer = new EventHubProducerClient(connectionString, eventHubName))
{
using EventDataBatch eventBatch = await producer.CreateBatchAsync();
eventBatch.TryAdd(new EventData(new BinaryData("First")));
eventBatch.TryAdd(new EventData(new BinaryData("Second")));
await producer.SendAsync(eventBatch);
}
I don't think the following is the best idiomatic F# although it works:
let producerClient = EventHubProducerClient(connectionString, eventHubName)
let cancellationToken = CancellationToken()
let eventDataBatch =
cancellationToken
|> producerClient.CreateBatchAsync
let edb = eventDataBatch.Result
edb.TryAdd event
producerClient.SendAsync edb
note: I've not included the code to create the event but it's a JSON string.
How can I avoid the call to Result? This looks like a step that could be much cleaner.
You can rewrite code that uses C# async/await using the task { .. } computation expression in F#. Inside this, you can use let! in place of await, but also do! for awaiting tasks that do not return result and use! for awaiting IDisposable results.
I'm not sure what library are you using here, but something like this illustrates the syntax:
let connectionString = "<< CONNECTION STRING FOR THE EVENT HUBS NAMESPACE >>";
let eventHubName = "<< NAME OF THE EVENT HUB >>";
let processEvent() = task {
use producer = new EventHubProducerClient(connectionString, eventHubName)
use! eventBatch = producer.CreateBatchAsync()
eventBatch.TryAdd(EventData(new BinaryData("First")))
eventBatch.TryAdd(EventData(new BinaryData("Second")))
do! producer.SendAsync(eventBatch) }
If you then call processEvent(), the result will again be Task. You can ignore that (and let the computation run), or wait for the result of that, if you intend to block at the top level.
Hi I have a question about async in F#.
So I have a simple procedure that runs in background that is placed in a member of a type and it looks like:
type Sender() =
member this.Start(udpConectionPool) = async {
(* Some operation that continuously sends something over udp*)
} |> Async.Start
So this starts and begins to continuously sends frames over UDP without blocking rest of the program, but from time to time i want to restart thread (let us say i want to add new endpoint it would send it to that is udpConnectionPool parameter).
I was thinking about something like dumping task to member and then:
member this.Stop() = async {
do! (*stop async start member that contains task*)
}
And then I can restart this task with updated connection pool, but I don't know if I can do that.
My question is, Is it possible to stop such task, or if not is there a better way to do it?
The standard way of cancelling F# async workflows is using a CancellationToken. When you call Async.Start, you can provide a cancellation token. When the token gets cancelled, the async workflow will stop (after the current blocking work finishes):
open System.Threading
let cts = new CancellationTokenSource()
let work = async { (* ... *) }
Async.Start(work, cts.Token)
cts.Cancel() // Sometime later from another thread
To integrate this with the Sender, you could either store the current CancellationTokenSource and have a Stop method that cancels it (if you want to keep this inside a stateful class). Alternatively, you could return IDisposable from the Start method in a way that is similar to how the Observable interface work:
type Sender () =
member this.Start(udpConnectionPool) =
let cts = new CancellationTokenSource()
let work = async { (* ... *) }
Async.Start(work, cts.Token)
{ new System.IDisposable with
member x.Dispose() = cts.Cancel() }
This way, the caller of Start is responsible for storing the returned IDisposable and disposing of it before calling Start again.
I suspect that my understanding of Streams in Dart might have a few holes in it...
I have a situation in which I'd like a Dart app to respond to intermittent input (which immediately suggests the use of Streamss -- or Futures, maybe). I can implement the behavior I want with listener functions but I was wondering how to do this in a better, more Dartesque way.
As a simple example, the following (working) program listens to keyboard input from the user and adds a div element to the document containing what has been typed since the previous space, whenever the space bar is hit.
import 'dart:html';
main() {
listenForSpaces(showInput);
}
void listenForSpaces(void Function(String) listener) {
var input = List<String>();
document.onKeyDown.listen((keyboardEvent) {
var key = keyboardEvent.key;
if (key == " ") {
listener(input.join());
input.clear();
} else {
input.add(key.length > 1 ? "[$key]" : key);
}
});
}
void showInput(String message) {
document.body.children.add(DivElement()..text = message);
}
What I'd like to be able to do is to create a new Stream from the Stream that I'm listening to (in the example above, to create a new Stream from onKeyDown). In other words, I might set the program above out as:
var myStream = ...
myStream.listen(showInput);
I suspect that there is a way to create a Stream and then, at different times and places, insert elements to it or call for it to emit a value: it feels as though I am missing something simple. In any case, any help or direction to documentation would be appreciated.
Creating a new stream from an existing stream is fairly easy with an async* function.
For a normal stream, I would just do:
Stream<String> listenForSpaces() async* {
var input = <String>[];
await for (var keyboardEvent in document.onKeyDown) {
var key = keyboardEvent.key;
if (key == " ") {
yield input.join();
input.clear();
} else {
input.add(key.length > 1 ? "[$key]" : key);
}
}
}
The async* function will propagate pauses through to the underlying stream, and it may potentially pause the source during the yield.
That may or may not be what you want, since pausing a DOM event stream can cause you to miss events. For a DOM stream, I'd probably prefer to go with the StreamController based solution above.
There are several methods and there is a whole package rxdart to allow all kinds of things.
Only the final consumer should use listen and only if you need to explicitly want to unsubscribe, otherwise use forEach
If you want to manipulate events like in your example, use map.
I wasn't originally planning to answer my own question but I have since found a very simple answer to this question in the dartlang creating streams article; in case it's helpful to others:
Specifically, if we'd like to create a stream that we can insert elements into at arbitrary times and places in the code, we can do so via the StreamController class. Instances of this class have an add method; we can simply use the instance's stream property as our stream.
As an example, the code in my question could be rewritten as:
import 'dart:html';
import 'dart:async';
main() async {
// The desired implementation stated in the question:
var myStream = listenForSpaces();
myStream.listen(showInput);
}
Stream<String> listenForSpaces() {
// Use the StreamController class.
var controller = StreamController<String>();
var input = List<String>();
document.onKeyDown.listen((keyboardEvent) {
var key = keyboardEvent.key;
if (key == " ") {
// Add items to the controller's stream.
controller.add(input.join());
input.clear();
} else {
input.add(key.length > 1 ? "[$key]" : key);
}
});
// Listen to the controller's stream.
return controller.stream;
}
void showInput(String message) {
document.body.children.add(DivElement()..text = message);
}
(As mentioned in the article, we need to be careful if we want to set up a stream from scratch like this because there is nothing to stop us from inserting items to streams that don't have associated, active subscribers; inserted items would in that case be buffered, which could result in a memory leak.)
I’ve implemented my own binary message protocol for simple request/response objects from a Dart client to a Java server. These are encoded in Dart as an Uint8List and on the remote server in Java as a ByteBuffer. The round trip works for the WebSocket in [dart:io] because the websocket.listen stream handler in the Dart client command app is passed data typed as Uint8List.
In [dart:html] the response data in MessageEvent.data received from the websocket.onMessage stream is typed as Blob. I’m not finding a way to convert the Blob to Uint8List. Because the response will often be a large binary array of numbers (double) that will be supplying data to a virtual scrolling context, I want to minimize copying. Could someone please point me in the right direction.
According to this article, you need to use a FileReader to do this.
This example seems to work, the result type is a Uint8List when I tested this in Chrome.
var blob = new Blob(['abc']);
var r = new FileReader();
r.readAsArrayBuffer(blob);
r.onLoadEnd.listen((e) {
var data = r.result;
print(data.runtimeType);
});
Another option is to set WebSocket.binaryType to "arraybuffer". Then MessageEvent.data will return a ByteBuffer which can be turned into a Uint8List. See the example below.
import 'dart:html';
import 'dart:typed_data';
void main() {
var ws = new WebSocket('...')..binaryType = 'arraybuffer';
ws.onMessage.listen((MessageEvent e) {
ByteBuffer buf = e.data;
var data = buf.asUint8List();
// ...
});
}
Before saving an uploaded csv file I want to check it will parse. When I was just saving the file everything was fine, now that I'm reading it first the file saved is blank.
Here is my action method
[HttpPost]
public ActionResult Import(HttpPostedFileBase file)
{
// Check parse went ok
using (var fileStream = file.InputStream)
{
if (!MemberFileParsingService.CheckFileWillParse(fileStream))
{
ViewBag.Message = "There was a problem with the file";
return View();
}
}
// Save file so we can work on it in next action
file.SaveAs(Server.MapPath(fileName));
return RedirectToAction("ImportMatch", new { club = ActiveClub.Url });
}
And here's my method that checks to see if the file parses ok. It uses CsvReader to read through the whole file to check there are no errors. CsvReader throws exceptions when it comes to bad bits of the file.
public static bool CheckFileWillParse(Stream fileStream)
{
try
{
using (var reader = new StreamReader(fileStream))
{
using (CsvReader csv = new CsvReader(reader, false))
{
while (csv.ReadNextRecord()) { }
}
}
}
catch(Exception)
{
return false;
}
return true;
}
I think it's probably because it's trying to write the file using the same stream that is now at the end of the file. I don't know how to reset the stream though. I was hoping all my using statements would fix that problem.
So how can I reset the stream, or is that just a red herring?
Update: Found the length of the stream gets reset to zero after going through CheckFileWillParse so looks like resetting the stream is just a red herring and the stream is actually being blanked somehow.
You have to rewind the stream (if possible). Once you are doing reading it, the current position is at the end of the stream, that is why the file is empty when you save it.
You can use either the Seek function or the Position property to do this (set it to 0). Not all stream types support this though.
If a stream type doesn't support it, you may need to write the file out to disk first, then run your test against it.
Have you considered creating a copy of the stream to analyse, using Stream.CopyTo()?
Because of the using statement, the Dispose() method on your StreamReader object will be called. This will actually close the underlying Stream object. Hence why the stream is of zero length.
Option 1:
One option is to not dispose of the StreamReader instance by removing the using statement. You will need to manually dispose of the stream later (but maybe CsvReader will do this for you) by calling its Dispose() method.
The garbage collector will clean up the StreamReader object and will not close the underlying stream.
Option 2:
You can use the following constructor when instantiating StreamReader:
public StreamWriter(
Stream stream,
Encoding encoding,
int bufferSize,
bool leaveOpen
)
Setting the leaveOpen parameter to true will ensure that the stream will not be closed.
Since the StreamReader Dispose Method will dispose your underlying Stream as well.
MemoryStream ms = new MemoryStream();
myStream.CopyTo(ms);
myStream.Position = ms.Position = 0; // !Don't forget this!
//And then read your 'ms' here