Получить работоспособность системы с помощью C#

Есть ли простой способ получить работоспособность системы с помощью C#?

10 ответов

Решение
public TimeSpan UpTime {
    get {
        using (var uptime = new PerformanceCounter("System", "System Up Time")) {
            uptime.NextValue();       //Call this an extra time before reading its value
            return TimeSpan.FromSeconds(uptime.NextValue());
        }
    }
}

Я немного опоздал, но другой простой способ - использовать функцию GetTickCount64, которая доступна, начиная с Windows Vista, и не переполняется, как это делает GetTickCount:

public static TimeSpan GetUpTime()
{
    return TimeSpan.FromMilliseconds(GetTickCount64());
}

[DllImport("kernel32")]
extern static UInt64 GetTickCount64();

System.Environment.TickCount получает количество миллисекунд с момента перезапуска системы.

Остерегайтесь, однако, что это Int32 и переполнится через 24,9 дня и станет отрицательным. Смотрите замечания по документам MDSN.

Моя машина работает без перерыва 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);

Если вы используете более позднюю версию .NET (Core 3.0/.NET 5.0 или выше), то Environmentкласс теперь имеет свойство TickCount64.

Это не страдает от проблем с переносом TickCountсвойство, и вам не нужно прибегать к P/Invoke, чтобы получить значение.

      long tickCountMs = Environment.TickCount64;
var uptime = TimeSpan.FromMilliseconds(tickCountMs);

Самый простой и правильный способ сделать это

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();
}

Просто, нет, но это можно сделать:

    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!");
    }

Я знаю, что вопрос является старым и решенным, но самое простое решение, о котором я могу вспомнить, это просто использование свойства 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.
  */
Другие вопросы по тегам