Was profiling my code and found that the way we are doing colored console text is very expensive (majority of the runtime).
DateTime dt = DateTime.Now;
for (int i = 0; i <= 20000; i++)
{
ConsoleColor cf = Console.ForegroundColor;
ConsoleColor cb = Console.BackgroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.BackgroundColor = ConsoleColor.Blue;
Console.WriteLine("Hello World");
Console.ForegroundColor = cf;
Console.BackgroundColor = cb;
}
System.Diagnostics.Debug.WriteLine((DateTime.Now - dt).TotalMilliseconds);
This simple loop takes 2.8 seconds to run on my machine. If I just do the WriteLine, its only 600ms.
Now, before I get troll answers :) asking why I keep setting the color when its hardcoded, THIS IS TEST CODE, in the real code, the foreground and background colors are calculated on a few different factors. That part is irrelevant. This code is just assuming that the color will change and thus saves the originals, changes the colors, then changes it back to the original.
I've also tried using the native SetConsoleTextAttribute method through pinvoke since using ILSpy, it seemed like the Console.xxx methods were doing a lot of extra crap, but I got about the same timings.
Not really. As you've already noted, the properties built in to Console interact with SetConsoleTextAttribute directly, which is the way to set console output properties in Windows.
If ANSI colors are an option, which would be substantial changes to logic you have working with console colors, it is faster. A minimal case
for (int i = 0; i <= 20000; i++)
{
Console.WriteLine("\x1b[31m\x1b[44mHello World\x1b[39m\x1b[49m");
}
runs in about 1200 ms on my machine, compared to about 7000 ms with the Console.xxxColor properties.
You'll need a compatible shell. Ansicon works.
With ANSI colors, you can additionally batch your output for even more times savings. Even batches of lines of 20 chop the run time above in half.* If you're spamming to the console for whatever reason, that could help significantly.
*On my machine.
See this answer to "How can I write fast colored output to Console?" and note this solution requires p-invoking of WriteConsoleOutput.
The color information is in the CharInfo struct, using Console.ForegroundColor in the lower 4 bits and BackgroundColor in the upper 4 bits of the short Attributes field.
Here is the constructor I use for the struct:
public CharInfo(char character, ConsoleColor? foreground = null, ConsoleColor? background = null) {
this.Char = new CharUnion() { UnicodeChar = character };
this.Attributes = (ushort)((int)(foreground ?? 0) | (((int)(background ?? 0)) << 4));
}
(you will also need to have CharSet=CharSet.Unicode in a couple places in the [StructLayout...] attributes to get Unicode to work)
Do some buffering by constructing an array CharInfo[] sized for the console window, then flush it to screen all at once for immensely-fast* updates!
*Fast relative Console.Write... methods at least. 160x80 can still take over 100ms.
Related
As a part of a bigger project I wrote the terminal emulator. Everything work file except one problem. I do not understand the connection between the values properties of the font (size) and screen pixels.
Font
TermFont = new Font(FontFamily.GenericMonospace, fsize, GraphicsUnit.Pixel);
Tested with another units as well.
number of characters I can display (both methods and both do not work).
//FontSizef = tg.MeasureString(testString, TermFont);
//int xchars = (int)(p.Width / FontSizef.Width) + 1;
//int ychars = (int)(p.Height / FontSizef.Height);
int xchars = (int)(p.Width / TermFont.Size) + 1;
int ychars = (int)(p.Height / TermFont.Height);
The first measuring method (commented). I measure the size of the one character string. As it is monospaced font all letters should have the same size. Tested both methods. Result is exactly the same.
The problem
It is giving me too low number of characters
So it looks like this:
Probably I do not understand how the unit system works.
Help appreciated ::
I have very uncanny problem about Win32 console.
There are missing pixels in the console cell like that:
Okay, let's consider the problem a little bit more detailed. I figure out the bug comes, when all of this 3 factors are available:
We must use symbol that we can see the first column of pixels is missing, so 'i' will be useless in our case, because it's printed on middle of the cell, but character like '0', or better '\u2593' (which is filling the cell fully) is going to be good choice as well:
char myChar = '\u2593';
Also need to change the Console.ForegroundColor different from our default console color. For example - Yellow:
Console.ForegroundColor = ConsoleColor.Yellow;
Finally, print symbols backward through moving the cursor position, so we're going to use at least twо times this lines:
Console.SetCursorPosition(left, 0);
Console.Write(myChar);
Now we are ready to simulate our problem with the following code:
static void Main()
{
char myChar = '\u2588';
Console.ForegroundColor = ConsoleColor.Yellow;
for (int i = 5; i >= 0; i--)
{
Console.SetCursorPosition(i, 0);
Console.Write(myChar);
Console.SetCursorPosition(i, 0);
Console.Write(myChar);
}
Console.WriteLine();
}
The problem can be observe even more clearly in this console snake game:
Here's an explanation of the previous one screenshot:
So, is it possible to get rid of this irritating effect of cracked ASCII, given that I use filling symbols, change the console colors and print backward?
I'm trying to read all of the feature data from particular shapefile. In this case, I'm using DotSpatial to open the file, and I'm iterating through the features. This particular shapefile is only 9mb in size, and the dbf file is 14mb. There is roughly 75k features to loop through.
Note, this is all programmatically through a console app, so there is no rendering or anything involved.
When loading the shape file, I reproject, then I'm iterating. The loading an reprojecting is super quick. However, as soon as the code reaches my foreach block, it takes nearly 2 full minutes to load the data, and uses roughly 2GB of memory when debugging in VisualStudio. This seems very, very excessive for what's a reasonably small data file.
I've ran the same code outside of Visual Studio, from the command line, however the time is still roughly 2 full minutes, and about 1.3GB of memory for the process.
Is there anyway to speed this up at all?
Below is my code:
// Load the shape file and project to GDA94
Shapefile indexMapFile = Shapefile.OpenFile(shapeFilePath);
indexMapFile.Reproject(KnownCoordinateSystems.Geographic.Australia.GeocentricDatumofAustralia1994);
// Get's slow here and takes forever to get to the first item
foreach(IFeature feature in indexMapFile.Features)
{
// Once inside the loop, it's blazingly quick.
}
Interestingly, when I use the VS immediate window, it's super super fast, no delay at all...
I've managed to figure this out...
For some reason, calling foreach on the features is painfully slow.
However, as these files have a 1-1 mapping with features - data rows (each feature has a relevant data row), I've modified it slightly to the following. It's now very quick.. less than a second to start the iterations.
// Load the shape file and project to GDA94
Shapefile indexMapFile = Shapefile.OpenFile(shapeFilePath);
indexMapFile.Reproject(KnownCoordinateSystems.Geographic.Australia.GeocentricDatumofAustralia1994);
// Get the map index from the Feature data
for(int i = 0; i < indexMapFile.DataTable.Rows.Count; i++)
{
// Get the feature
IFeature feature = indexMapFile.Features.ElementAt(i);
// Now it's very quick to iterate through and work with the feature.
}
I wonder why this would be. I think I need to look at the iterator on the IFeatureList implementation.
Cheers,
Justin
This has the same problem for very large files (1.2 millions of features), populating .Features collections never ends.
But if you ask for the feature you do not have memory or delay overheads.
int lRows = fs.NumRows();
for (int i = 0; i < lRows; i++)
{
// Get the feature
IFeature pFeat = fs.GetFeature(i);
StringBuilder sb = new StringBuilder();
{
sb.Append(Guid.NewGuid().ToString());
sb.Append("|");
sb.Append(pFeat.DataRow["MAPA"]);
sb.Append("|");
sb.Append(pFeat.BasicGeometry.ToString());
}
pLinesList.Add(sb.ToString());
lCnt++;
if (lCnt % 10 == 0)
{
pOld = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.Write("\r{0} de {1} ({2}%)", lCnt.ToString(), lRows.ToString(), (100.0 * ((float)lCnt / (float)lRows)).ToString());
Console.ForegroundColor = pOld;
}
}
Look for the GetFeature method.
I have a large list of offsets which I need to highlight in my RichTextBox. However this process is taking too long. I am using the following code:
foreach (int offset in offsets)
{
richTextBox.Select(offset, searchString.Length);
richTextBox.SelectionBackColor = Color.Yellow;
}
Is there a more efficient way to do so?
UPDATE:
Tried using this method but it doesn't highlight anything:
richTextBox.SelectionBackColor = Color.Yellow;
foreach (int offset in offsets)
{
richTextBox.Select(offset, searchString.Length);
}
I've googled your issue and I found that RichTextBox is getting very slow when having many lines. In my opinion, you have either buy a third part control which you can be satisfied by its performance or you may need threads to devide the whole selection task. I think they can accelerate things up.
Hope it helps !
I've had this same problem before. I ended up disregarding all of the methods they give you and manipulated the underlying RTF data. Also, the reason that your second block of code doesnt work is that RTF applies formatting as it goes, so if you call a function (or Property in this case) to change the selection color, it will only apply it for the currently selected block. Any changes made to the selection after that call become irrelavent.
You can play around with the RGB values, or here is a great source on how to do different things within the RTF control. Pop this function in your code and see how well it works. I use it to provide realtime syntax highlighting for SQL code.
public void HighlightText(int offset, int length)
{
String sText = richTextBox.Text.Trim();
sText = sText.Insert(offset + length - 1, #" \highlight0");
sText = sText.Insert(offset, #" \highlight1");
String s = #"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Courier New;}}
{\colortbl ;\red255\green255\blue0;}\viewkind4\uc1\pard";
s += sText;
s += #"\par}";
richTextBox.Rtf = s;
}
Does it make any difference if you set the SelectionBackColor outside of the loop?
Looking into the RichTextBox with Reflector shows, that a WindowMessage is sent to the control every time when the color is set. In the case of large number of offsets this might lead to highlighting the already highlighted words again and again, leading to O(n^2) behavior.
So I've been working on cobbling together a game and decided I'd like to have a little program to show a file with each character replaced by its byte equivalent for working with coding saves and whatnot. Figured it'd a layup. Three hours later, I've been wracking my brain trying to figure this out.
When I load a small (or perhaps short is the better term) file it looks like the window on top. When I load a larger file, it looks like the window on the bottom.
http://dl.dropbox.com/u/16985121/Images/ViewAsBytes.PNG
That's 10pt Courier New, but it seems to happen with any font I try. There's always that extra column, and if there wasn't enough room for the column, it'd just squeeze in whatever it could in that space that it previously didn't use. I've tried tweaking all kinds of variables, as well as comparing the textbox before and after it adds the text from the file (which is read in just as bytes from a FileStream and then fed into a StringBuilder) but nothing seems to change even though something is clearly different.
I can think of a bunch of different workarounds for this, but now I'm just more interested in what TextBox thinks it's doing exactly than getting my program done. Anyone got any idea?
Here's the code that reads in the data and puts that to the textbox:
FileStream stream = new FileStream(files[0], FileMode.Open);
StringBuilder sb = new StringBuilder();
int byteIn = stream.ReadByte();
while (byteIn != -1)
{
sb.Append('[');
if (byteIn < 100)
sb.Append('0');
if (byteIn < 10)
sb.Append('0');
sb.Append(byteIn.ToString());
sb.Append(']');
byteIn = stream.ReadByte();
}
txtView.Text = sb.ToString();
stream.Close();
This is because you set to the WordWrap property to True. Set it to False, set Multiline to True and ScrollBars to Both. Append Environment.NewLine to the string you generate, every 16 bytes is the norm for hex viewers. Use byte.ToString("X2") to generate a hex string instead of a decimal string.
You now have a full scrollable view of the data, any amount is supported. Allow the user to resize the window so she won't have to scroll horizontally. Or just make it big enough.