Есть ли простой способ получить время безотказной работы системы с помощью С#?
Получить время безотказной работы системы с помощью C#
Ответы (10)
Я немного опоздал, но другой простой способ — использовать GetTickCount64, которая доступна, начиная с Windows Vista, и не вызывает переполнения, как это делает GetTickCount:
public static TimeSpan GetUpTime()
{
return TimeSpan.FromMilliseconds(GetTickCount64());
}
[DllImport("kernel32")]
extern static UInt64 GetTickCount64();
GetTickCount64 ... does not overflow
- Он переполнится, когда они найдут способ заставить мой код работать 585 миллиардов лет.
- person rkagerer; 23.11.2015
GetTickCount
— это API производительности, рассчитанный на основе структур ядра, которые в то время были 32-битными, GetTickCount64
появились после того, как эти структуры ядра стали поддерживать 64-битные значения. Возможно, стоит отметить, что GetTickCount
изначально предназначался для обеспечения временной корреляции между счетчиками производительности системы в течение короткого периода, использование, которое позже было заменено QueryPerformanceCounter
для корреляции с более высоким разрешением в течение более длительного периода.
- person Shaun Wilson; 12.03.2018
TickCount64
свойство.
- person Steven Rands; 02.03.2021
Environment.TickCount64
? Я думаю, что это сейчас лучшее решение.
- person Martin; 03.03.2021
System.Environment.TickCount получает количество миллисекунд с момента система была перезапущена.
Остерегайтесь, однако, что это Int32, и он переполнится через 24,9 дня и станет отрицательным. См. примечания к документам MDSN.
UInt32
/uint
.
- person Slipp D. Thompson; 14.04.2014
TickCount64
, что позволяет избежать проблемы переноса.
- person Steven Rands; 02.03.2021
Моя машина имеет время безотказной работы 58 days 17 hours
в соответствии с диспетчером задач. Я прошел и попробовал каждый ответ здесь, и быстрые ответы немного отключены (примерно ~ 1-3 минуты, но более 58 дней безотказной работы):
Stopwatch.GetTimeStamp(): 58days 17hours 11minutes 25seconds
~Time to calculate (ms): 6.8413
DllImport GetTickCount64(): 58days 17hours 13minutes 34seconds
~Time to calculate (ms): 0.2192
PerformanceCounter(System, System Up Time): 58days 17hours 14minutes 02seconds
~Time to calculate (ms): 1233.2854
ManagementObject LastBootUpTime: 58days 17hours 14minutes 02seconds
~Time to calculate (ms): 30.0283
Последние два, с использованием PerformanceCounter или с помощью ManagementObject, всегда находятся в пределах той же секунды, что и диспетчер задач Windows (просто нужно поверить мне на слово или попробовать самостоятельно с кодом ниже). Основываясь на результатах, я собираюсь использовать метод ManagementObject LastBootUpTime
, потому что он намного быстрее, чем PerformanceCounter
, но все же совершенно точен по сравнению с диспетчером задач.
Обратите внимание, что я вычел текущее прошедшее время из каждого метода перед печатью времени, но все это занимает менее 2 секунд, поэтому временной сдвиг в любом случае нельзя объяснить неправильным учетом времени выполнения. Вот код, который я использовал:
[System.Runtime.InteropServices.DllImport("kernel32")]
extern static UInt64 GetTickCount64();
public static void Main()
{
var start = Stopwatch.StartNew();
var eachStart = Stopwatch.StartNew();
var ticks = Stopwatch.GetTimestamp();
var uptime = ((double)ticks) / Stopwatch.Frequency;
var uptimeTimeSpan = TimeSpan.FromSeconds(uptime);
Console.WriteLine("Stopwatch.GetTimeStamp(): " + uptimeTimeSpan.Subtract(start.Elapsed).ToString(@"dd\d\a\y\s\ hh\h\o\u\r\s\ mm\m\i\n\u\t\e\s\ ss\s\e\c\o\n\d\s"));
Console.WriteLine($"~Time to calculate (ms): {eachStart.Elapsed.TotalMilliseconds}");
eachStart.Restart();
Console.WriteLine("DllImport GetTickCount64(): " + TimeSpan.FromMilliseconds(GetTickCount64()).Subtract(start.Elapsed).ToString(@"dd\d\a\y\s\ hh\h\o\u\r\s\ mm\m\i\n\u\t\e\s\ ss\s\e\c\o\n\d\s"));
Console.WriteLine($"~Time to calculate (ms): {eachStart.Elapsed.TotalMilliseconds}");
eachStart.Restart();
var upTime = new PerformanceCounter("System", "System Up Time");
upTime.NextValue(); //Call this an extra time before reading its value
Console.WriteLine("PerformanceCounter(System, System Up Time): " + TimeSpan.FromSeconds(upTime.NextValue()).Subtract(start.Elapsed).ToString(@"dd\d\a\y\s\ hh\h\o\u\r\s\ mm\m\i\n\u\t\e\s\ ss\s\e\c\o\n\d\s"));
Console.WriteLine($"~Time to calculate (ms): {eachStart.Elapsed.TotalMilliseconds}");
eachStart.Restart();
ManagementObject mo = new ManagementObject(@"\\.\root\cimv2:Win32_OperatingSystem=@");
DateTime lastBootUp = ManagementDateTimeConverter.ToDateTime(mo["LastBootUpTime"].ToString());
Console.WriteLine("ManagementObject LastBootUpTime: " + (DateTime.Now.ToUniversalTime() - lastBootUp.ToUniversalTime()).Subtract(start.Elapsed).ToString(@"dd\d\a\y\s\ hh\h\o\u\r\s\ mm\m\i\n\u\t\e\s\ ss\s\e\c\o\n\d\s"));
Console.WriteLine($"~Time to calculate (ms): {eachStart.Elapsed.TotalMilliseconds}");
}
Точно и больше, чем System.Environment.TickCount
, без использования ужасных счетчиков производительности ОС, WMI или собственных вызовов:
var ticks = Stopwatch.GetTimestamp();
var uptime = ((double)ticks) / Stopwatch.Frequency;
var uptimeSpan = TimeSpan.FromSeconds(uptime);
Stopwatch.GetTimestamp()
тогда не включает время сна компьютера? Пожалуйста, объясни.
- person Rbjz; 12.01.2015
GetTimestamp()
включает время сна. Но я не знаю точного ответа на ваш вопрос.
- person Martin; 12.01.2015
Самый простой и правильный способ сделать это
public static TimeSpan GetUptime()
{
ManagementObject mo = new ManagementObject(@"\\.\root\cimv2:Win32_OperatingSystem=@");
DateTime lastBootUp = ManagementDateTimeConverter.ToDateTime(mo["LastBootUpTime"].ToString());
return DateTime.Now.ToUniversalTime() - lastBootUp.ToUniversalTime();
}
Invalid object path
на сервере Windows 2003, работающем в веб-службе в IIS6.
- person Hugh Jeffner; 11.01.2011
Просто, нет, но это можно сделать:
static DateTime getLastBootTime(ManagementObject mObject)
{
PropertyData pd = mObject.Properties["LastBootUpTime"];
string name = pd.Name.ToString();
DateTime lastBoot = parseCmiDateTime(pd.Value.ToString());
return lastBoot;
}
static ManagementObject getServerOSObject(string serverName)
{
ManagementObjectSearcher mSearcher = new ManagementObjectSearcher("Select * From Win32_OperatingSystem");
mSearcher.Scope = new ManagementScope(String.Format(@"\\{0}\root\cimv2", serverName));
ManagementObjectCollection mObjects = mSearcher.Get();
if (mObjects.Count != 1) throw new Exception(String.Format("Expected 1 object, returned {0}.", mObjects.Count));
foreach (ManagementObject m in mObjects)
{
//No indexing on collection
return m;
}
throw new Exception("Something went wrong!");
}
Если вы используете более позднюю версию .NET (Core 3.0/.NET 5.0 или выше), то класс Environment
теперь имеет свойство TickCount64.
Это не страдает от проблем с переносом свойства TickCount
, и вам не нужно прибегать к P/Invoke, чтобы получить значение.
long tickCountMs = Environment.TickCount64;
var uptime = TimeSpan.FromMilliseconds(tickCountMs);
Я знаю, что вопрос и старый, и решенный, но самое простое решение, которое я могу придумать, - это просто использовать свойство Enviroment.TickCount, которое возвращает количество миллисекунд с момента запуска системы:
System.DateTime SystemStartTime = DateAndTime.Now.AddMilliseconds(-Environment.TickCount);
System.DateTime Uptime = DateAndTime.Now - SystemStartTime;
Это решение намного быстрее, чем принятый ответ.
(Один и единственный) правильный ответ на данный момент:
Использование 32-битного таймера невероятно опасно и чревато ошибками при любом использовании, кроме ограниченного.
Я не уверен, когда материал класса NativeMethods был добавлен в .net, но это было. Вы определенно хотите избежать накладных расходов P/Invoke. Сделай это:
using System;
using System.Runtime.InteropServices;
namespace Mu
{
// prevents PInvoke (not in NativeMethods class) or Stack walk (NativeMethods class) performance penalties.
internal static partial class SafeNativeMethods
{
[DllImport("kernel32")]
internal extern static UInt64 GetTickCount64();
}
public static class MuTime
{
public static UInt64 UpTimeMillis { get { return SafeNativeMethods.GetTickCount64(); } }
}
}
/*
Dual License (use either, not both). To avoid CC-BY-SA, access a copy of this
code at (https://pastebin.com/6EKTWsSf) to use under BSD 0-clause license,
Copyright (c) 2020 Robin Davies
CC-BY-SA 3.0 (due to StackExchange terms of use). Not my fault, blame StackExchange. Fix this
please, StackExchange!
BSD 0-Clause
Copyright 2020 Robin Davies.
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/
[DllImport]
является использованием P/Invoke, верно?
- person Steven Rands; 02.03.2021
StringBuilder buffer = new StringBuilder(1024); uint buf_size = (uint)buffer.Capacity; Win32.PdhLookupPerfNameByIndex(null, id, buffer, ref buf_size); return buffer.ToString();
- person Oliver Bock; 24.07.2013
GetTickCount64
(не во всех версиях Windows) или ZwQuerySystemInformation
(отменить документ), или sysinfo
(в системах posix+SVR4)
- person Shaun Wilson; 12.03.2018