How come my program takes so long to run? - c#

I have written a short code in C# in order to take out the text output generated from the Lyx software and modifies it so I could post it on Math.SE.
The code assumes I have a file on my desktop called answer.txt, reads the file and then modifies the code, then it saves the output as answer2.txt at my desktop: For example, the text generated by Lyx have the first line "% Preview body" which I remove. another example is replacing
\textbf{some text that should be bold}
with
**some text that should be bold**
This is the code I have written:
class Program
{
static void Main(string[] args)
{
using (StreamReader sr = new StreamReader(#"C:\Users\BelgiAmir\Desktop\answer.txt"))
{
string text = sr.ReadToEnd();
string AfterFirstReplacement = text.Replace("\\[", "$$");
string AfterSecondReplacement = AfterFirstReplacement.Replace("\\]", "$$");
string RemovedPreviewHeader = AfterSecondReplacement.Replace("% Preview body", "");
int indexOfBold ;
while ((indexOfBold = RemovedPreviewHeader.IndexOf("\\textbf")) != - 1)
{
indexOfBold = RemovedPreviewHeader.IndexOf("\\textbf");
int endIndex = RemovedPreviewHeader.IndexOf("}", indexOfBold);
string boldedText = RemovedPreviewHeader.Substring(indexOfBold + 8, endIndex - indexOfBold - 8);
RemovedPreviewHeader = RemovedPreviewHeader.Replace("\\textbf{" + boldedText + "}",
"**" + boldedText + "**");
}
File.WriteAllText(#"C:\Users\BelgiAmir\Desktop\answer2.txt", RemovedPreviewHeader);
}
}
}
But my code seems to be slow, at least I don't think it is reasonable run time.
I tested the code in the following manner: I have the two empty answer.txt and answer2.txt on my desktop. The .exe file is also on the same hard drive (and on the same partition). I have opened the .exe file and used a plain stopwatch to measure a running time of
15.5 seconds
The files (.exe and the .txt files) are located on an SSD, my computer have 8gb of ram and an i5 Haswell processor (i5-4570). The OS is Windows 7 professional.
This seems like a very long running time - 15.5 seconds to open an empty .text file, then all string operations should be very fast as they are done on an empty string, and the while loop should not be preformed even once, then I save an empty file.
This is a code I have written a while ago and this is about the same running time I always get (even though I have restarted the computer since a couple of times and no "heavy" software is running on it)
Note: The code was written and compiled using VS 2013 express, I have tried running this test with both the Debug version of the .exe and both with a version for Release (and the running time was about the same)
Can someone suggest a reason for this long running time and how to fix it ?
ADDED: With running in Debug in VS and hitting F5 the code runs in less then two seconds! I don't know why it is so fast when I run it through VS then by opening the .exe file, can someone explain this ?

Related

Visual Studio C#/csc writes .dll output file more than once when building

I'm making an application that reloads a .dll whenever the file is written. That way when I build I auto-load the changes.
I'm using FileSystemWatcher like this (simplified):
const string DllDir = #"C:\blah\bin\Debug\net6.0";
const string DllFile = "dependency.dll";
static void Main(string[] args)
{
var stopwatch = Stopwatch.StartNew();
using var watcher = new FileSystemWatcher(DllDir, DllFile);
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Changed += (a, b) =>
{
stopwatch.Stop();
Console.WriteLine("Changed " + stopwatch.Elapsed);
stopwatch.Restart();
};
watcher.EnableRaisingEvents = true;
while (true) ;
}
but whenever I build the dependency.dll project, right-clicking from the IDE Solution Explorer or calling csc directly (csc /target:library C:\blah\Example.cs /out:C:\blah\bin\Debug\net6.0\dependency.dll), I get an output like this from the watcher program:
Changed 00:00:14.6056924
Changed 00:00:00.0000761
First the 14 second delay since I started the watcher program until the dll changed, and then 76 microseconds later it has changed again! I'm using Visual Studio 2022.
I have searched but still have absolutely no clue what's going on.
Can anybody explain me what's going on?
Is there a command line argument or some project configuration to avoid this?
I'm trying to get to build as fast as possible, so I want to understand which unnecessary step is doing this to disable it. Otherwise I think I can just copy the dll to another path on a post-build step, but would want to understand what the compiler is doing anyway.
Thank you
Apparently this has to do with the file watching not the build process. Adding a copy to the post-build step showed the same behavior on the destination path.
NotifyFilters documentation says:
LastWrite: The date the file or folder last had anything written to it.
But the OnChanged doc further expands on that:
OnChanged is called when changes are made to the size, system attributes, last write time, last access time, or security permissions of a file or directory
So probably there are multiple changes being made for a single build or copy.
Thanks to https://stackoverflow.com/a/60088655/10060021

Runtime error in script task

We have a fully running database server, say serverA, whose data are refreshed daily.
We want to duplicate this database on a different server, says serverB, so that we have a test environment. The databases has been restored to serverB.
Like serverA, we want serverB's data to be refreshed daily also, so the tests we conduct on serverB can be said as fully accurate since they will have the same data as serverA. We deployed the SSIS packages used in serverA in serverB and copied the SQL Server Agent Jobs in serverB also.
I am trying to modify these jobs and packages so that they can run smoothly on serverB, I'm changing directory paths, server names, etc.
Now, there is this job that always fails because of a package, zip.dtsx.
zip.dtsx retrieves files from directoryA, compresses them and saves the compressed file to directoryB, then deletes the file in directoryA. However, I cannot figure out why it's having a runtime error.
zip.dtsx has a script task named Zip files.
The script language is Microsoft Visual C# 2010
The ReadOnlyVariables set are User::DestinationPath, User::NamePart, User::SourcePath,$Package::filename
The script is,
public void Main()
{
String sourcePath = Convert.ToString(Dts.Variables["SourcePath"].Value);
String namePart = Convert.ToString(Dts.Variables["NamePart"].Value);
String destinationPath = Convert.ToString(Dts.Variables["DestinationPath"].Value);
FileStream sourceFile = File.OpenRead(#sourcePath + namePart);
FileStream destFile = File.Create(#destinationPath + namePart);
GZipStream compStream = new GZipStream(destFile, CompressionMode.Compress);
try
{
int theByte = sourceFile.ReadByte();
while (theByte != -1)
{
compStream.WriteByte((byte)theByte);
theByte = sourceFile.ReadByte();
}
}
finally
{
compStream.Dispose();
sourceFile.Close();
destFile.Close();
File.Delete(#sourcePath + namePart);
}
Dts.TaskResult = (int)ScriptResults.Success;
}
The error I'm getting, when I execute the task in Microsoft Visual Studio -> Right click Script Task object -> Execute task
I am not familiar with Microsoft Visual C# and I have just also begun using SSIS packages, so I'm really at a loss.
UPDATE:
I tried commenting out different lines in the C# script. Finally, when I commented out File.Delete(#sourcePath + namePart);, the job calling zip.dtsx has succeeded. However, I am not sure why I'm having an error with this line. I'm not sure if it is because of permissions or any other else.

Can't Access a xml file at random by C# console application

I have a C# console application which creates, parses and deletes multiple xml files at runtime. The application used to run fine in Windows 2003 server with .Net 2.0.
Recently, the Application framework was upgraded to >net 4.0 and the Windows Server OS to Windows 2008 64-bit.
Since then, the application encounters the following exception at random:
Access to the path 'D:\Content\iSDC\GDCOasis\GATE_DATA\LOG\635125008068192773\635125008074911566\SOD\AllRespId.xml' is denied.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.File.Delete(String path)
at ProcessGateFile.SOD.saveFile(String psFile, String psXMLString, Boolean isNonAscii)
The code for the creation, parsing and deletion is as follows:
saveFile(tmpPath + "\\SOD\\AllRespId.xml", "<?xml version= \"1.0\" ?><XML>" + sbldDistinctResp.ToString() + "</XML>", isChinese);
//Save list of Distinct responsibilities for User
sbldDistinctResp.Remove(0, sbldDistinctResp.Length);
xmlCase.Load(tmpPath + "\\SOD\\AllRespId.xml");
arrResps.Clear();
//Start preparing Responsibility selection criteria
RespNodes = xmlCase.SelectNodes("//row");
sRespCriteria = "";
if (RespNodes.Count > 0)
{
foreach (XmlNode RespNode in RespNodes)
{
string RespName = RespNode.Attributes.GetNamedItem("RespId").Value.ToString();
if (!arrResps.Contains(RespName))
{
arrResps.Add(RespName);
}
}
for (int i = 0; i < arrResps.Count; i++)
{
sbldDistinctResp.Append("(#RespId = '" + arrResps[i].ToString() + "') or ");
}
sbldDistinctResp.Remove(sbldDistinctResp.Length - 4, 4);
sRespCriteria = sbldDistinctResp.ToString();
if (!sRespCriteria.Equals(""))
{
sRespCriteria = "(" + sRespCriteria + ")";
}
}
File.Delete(tmpPath + "\\SOD\\AllRespId.xml");
I repeat, the error is happening at random, i.e. it works at times and does not at other times during the same process.
Any idea what might be causing this and how to resolve?
Just a couple of observations:
Why are you saving and then immediately loading the file again? In fact, why do you even need to save this file - you already have all the information you need in the sbldDistinctResp variable to generate the XML you need to work with (as evidenced by the saveFile call at the start of the code) - couldn't you just make a copy of it, surround it with the same XML as you did during saveFile, and work with that?
"It happens randomly" is a very subjective observation :). You should profile this (run it 10,000 times in a loop for example) and record the pattern of errors. You may well be surprised that what seems random at first actually shows a clear pattern over a large number of runs. This may help you to make a connection between the problem and some other apparently unrelated event on the server; or it may confirm that it truly is random and therefore outside of your control.
If you really can't find the problem and you go with the idea of anti-virus, etc, then you could wrap the loading code in a try/catch and re-try a couple of times if you get the error. It's hacky but it would work, assuming you have accepted that the initial error is beyond your control.

Run a c# Console App with .application file type from a .BAT

I've created a console app (using Visual Studio 2010) which can read command arguments.
When I debug, I parse some test parameters which are set in Project-> [project name] Properties... -> Debug -> Command line arguments:
It reads:
"parametername1|parametervalue1" "parametername2|parametervalue2" "parametername3|parametervalue3"
I used the following code to read the parameters:
for (Int16 argumentsCount = 0; argumentsCount < args.Length; argumentsCount++)
{
String[] parameterItem = args[argumentsCount].Split('|');
String parameterName = parameterItem[0].ToString();
String parameterValue = parameterItem[1].ToString();
/*code continues*/
}
When I run in debug mode the app it works just fine and all parameters are read.
I then published the app to a server and ensured it was installed with the correct permissions (for the purposes of demonstration lets say it's on C:\MyApp and the Complied code resides in MyApp.application
I then created a batch script that executes the app. The *.BAT contains the following command:
"C:\MyApp\MyApp.application" "parametername1|parametervalue1" "parametername2|parametervalue2" "parametername3|parametervalue3"
This kind of works as the application executes when I run the batch... However... none of my parameters are being received by my app. I know this because I recompiled and published with some code to read how many parameters are being received with:
Console.Write("Arguments " + args.Length.ToString());
and that shows Arguments: 0
Can someone please tell me how to write my batch script to run the app and parse my parameters/command line arguments.
ETA: Nevermind. Your problem is .application instead of a .exe. Look in your file associations what happens with .application compared to .exe:
> assoc .application
.application=Application.Manifest
> ftype Application.Manifest
Application.Manifest=rundll32.exe dfshim.dll,ShOpenVerbApplication %1
> assoc .exe
.exe=exefile
> ftype exefile
exefile="%1" %*
You see the difference in what is passed there? Namely that normal executables get command-line arguments (the %*). So I guess you should use an executable instead of an executable manifest or whatever .application actually is (I've never seen it in the wild, honestly).
With a fairly minimal test program
class Args {
static void Main(string[] args) {
for (int i = 0; i < args.Length; i++) {
System.Console.WriteLine("[{0}]=<{1}>", i, args[i]);
}
}
}
it works fine for me. The following batch file:
#"args.exe" "parametername1|parametervalue1" "parametername2|parametervalue2" "parametername3|parametervalue3"
yields the following output:
[0]=<parametername1|parametervalue1>
[1]=<parametername2|parametervalue2>
[2]=<parametername3|parametervalue3>
So I guess there is something wrong in the code you didn't show us. Maybe you're not actually using the command-line arguments in your C# application but instead reference a different string[] there?
The pipe character | has a special meaning in batch files. I would suggest using a different character to make things easier. Otherwise you have to use a Escape Character to use the pipe character. It would probably look like this:
"C:\MyApp\MyApp.application" "parametername1^|parametervalue1" "parametername2^|parametervalue2" "parametername3^|parametervalue3"
note the caret ^ before the pipe |.

Gems with .NET Applications - How do I set up the Executables so they run without error?

I have a gem, roundhouse, which is an application compiled with .NET (C#). Runs on Windows and it should run in a 32 bit process.
To set up my gemspec, I set:
Gem::Specification.new do |s|
s.platform = 'mswin32'
s.name = 'roundhouse'
s.version = version
s.files = Dir['lib/**/*'] + Dir['bin/**/*']
s.bindir = 'bin'
s.executables << 'rh.exe'
When I install the gem, I should be able to type rh.exe from the command line at any path and it should run correctly.
In practice, I'm not seeing this work correctly. This is what I'm getting back:
Window has this for the header: 16 bit MS-DOS Subsystem
C:\WINDOWS\system32\cmd.exe - rh.exe
The NTVDM CPU has encountered an illegal instruction.
CS:xxxx IP:xxxx OP:xx xx xx xx xx Choose 'Close' to terminate the application.
Here is a picture of the issue (link to TwitPic): Error
If I go to the directory where the item was installed, I can run it and it works great. It's just something in the registration of the command to run from anywhere.
I did quite a bit of searching before asking and came up with nothing. It could be that I don't know what I should be searching for. So let me ask the question, is there a way to register an executable with gems for windows executable applications (built with .NET) and have them register properly with the command line? If so, how is that done?
UPDATE:
I found that gems creates a shim in the C:\Ruby\bin directory that points back to the other file. So there is a rh.exe file that is really just a text file. This is its contents:
#!C:/Ruby/bin/ruby.exe
#
# This file was generated by RubyGems.
#
# The application 'roundhouse' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0"
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
version = $1
ARGV.shift
end
gem 'roundhouse', version
load Gem.bin_path('roundhouse', 'rh.exe', version)
if you're distributing it with the file "rh.exe"
then you'll want to create a file
bin/rh
s.executables << 'bin/rh'
then when it's installed gems will create an "rh.bat" file which runs ruby "bin/rh" essentially (as you've seen).
So within bin/rh put something like
result = system(File.dirname(__FILE__) + "/rh.exe" ARGV.join(' '))
exit 1 unless result
result = system(File.dirname(__FILE__) + "/rh.exe " + ARGV.join(' '))
exit 1 unless result
So the endresult should maybe look like? note the space after 'rh.exe'

Categories