v9.10.2019.0101 全面巩固批量Insert/Update/Upsert,支持数据备份、恢复和同步,支持实体列表保存到文件以及加载
|
# ÔËÐÐʱÐÅÏ¢ Runtime
## ¸ÅÊö
`Runtime` ÊÇ NewLife.Core ÖеÄÔËÐÐʱÐÅÏ¢¹¤¾ßÀ࣬Ìṩµ±Ç°ÔËÐл·¾³µÄ¸÷ÖÖ¼ì²âºÍ²Ù×÷¹¦ÄÜ¡£°üÀ¨²Ù×÷ϵͳÅжϡ¢»·¾³±äÁ¿¶ÁÈ¡¡¢ÄÚ´æ¹ÜÀí¡¢½ø³ÌÐÅÏ¢µÈ¹¦ÄÜ£¬ÊÇ¿çÆ½Ì¨¿ª·¢µÄÖØÒª»ù´¡×é¼þ¡£
**ÃüÃû¿Õ¼ä**£º`NewLife`
**ÎĵµµØÖ·**£ºhttps://newlifex.com/core/runtime
## ºËÐÄÌØÐÔ
- **ƽ̨¼ì²â**£ºWindows¡¢Linux¡¢OSX¡¢Mono¡¢Unity µÈÔËÐл·¾³Ê¶±ð
- **»·¾³ÅжÏ**£º¿ØÖÆÌ¨¡¢Web¡¢ÈÝÆ÷µÈÓ¦ÓÃÀàÐͼì²â
- **¸ß¾«¶È¼ÆÊ±**£º¿çƽ̨µÄ `TickCount64` ʵÏÖ£¬±ÜÃâ 32 λÒç³ö
- **ÄÚ´æ¹ÜÀí**£ºGC »ØÊպ͹¤×÷¼¯ÊÍ·Å
- **»·¾³±äÁ¿**£º²»Çø·Ö´óСдµÄ»·¾³±äÁ¿¶ÁÈ¡
## ¿ìËÙ¿ªÊ¼
```csharp
using NewLife;
// ÅжϲÙ×÷ϵͳ
if (Runtime.Windows)
Console.WriteLine("ÔËÐÐÔÚ Windows ϵͳÉÏ");
else if (Runtime.Linux)
Console.WriteLine("ÔËÐÐÔÚ Linux ϵͳÉÏ");
// ÅжÏÔËÐл·¾³
if (Runtime.IsConsole)
Console.WriteLine("¿ØÖÆÌ¨Ó¦ÓÃ");
if (Runtime.Container)
Console.WriteLine("ÔËÐÐÔÚÈÝÆ÷ÖÐ");
// »ñȡϵͳÔËÐÐʱ¼ä£¨ºÁÃ룩
var uptime = Runtime.TickCount64;
Console.WriteLine($"ϵͳÒÑÔËÐÐ {uptime / 1000 / 60} ·ÖÖÓ");
// »ñÈ¡µ±Ç°½ø³ÌID
var pid = Runtime.ProcessId;
Console.WriteLine($"µ±Ç°½ø³ÌID: {pid}");
// ÊÍ·ÅÄÚ´æ
Runtime.FreeMemory();
```
## API ²Î¿¼
### ƽ̨¼ì²â
#### Windows
```csharp
public static Boolean Windows { get; }
```
ÊÇ·ñ Windows ²Ù×÷ϵͳ¡£
**ʵÏÖ·½Ê½**£º
- .NET Core/.NET 5+£ºÊ¹Óà `RuntimeInformation.IsOSPlatform(OSPlatform.Windows)`
- .NET Framework£º¼ì²é `Environment.OSVersion.Platform`
**ʾÀý**£º
```csharp
if (Runtime.Windows)
{
// Windows ÌØÓеIJÙ×÷£¬Èçµ÷Óà Win32 API
Console.WriteLine("Windows °æ±¾: " + Environment.OSVersion.VersionString);
}
```
#### Linux
```csharp
public static Boolean Linux { get; }
```
ÊÇ·ñ Linux ²Ù×÷ϵͳ¡£
**ʾÀý**£º
```csharp
if (Runtime.Linux)
{
// Linux ÌØÓеIJÙ×÷£¬Èç¶ÁÈ¡ /proc Îļþϵͳ
var cpuInfo = File.ReadAllText("/proc/cpuinfo");
}
```
#### OSX
```csharp
public static Boolean OSX { get; }
```
ÊÇ·ñ macOS ²Ù×÷ϵͳ¡£
#### Mono
```csharp
public static Boolean Mono { get; }
```
ÊÇ·ñÔÚ Mono ÔËÐÐʱ»·¾³ÖÐÔËÐС£Í¨¹ý¼ì²â `Mono.Runtime` ÀàÐÍÊÇ·ñ´æÔÚÀ´Åжϡ£
**Ó¦Óó¡¾°**£º
- ijЩ API ÔÚ Mono ÏÂÐÐΪ²»Í¬
- Õë¶Ô Mono ½øÐÐÌØÊâÓÅ»¯»ò¼æÈÝ´¦Àí
#### Unity
```csharp
public static Boolean Unity { get; }
```
ÊÇ·ñÔÚ Unity ÒýÇæ»·¾³ÖÐÔËÐС£Í¨¹ý¼ì²â `UnityEngine.Application` ÀàÐÍÊÇ·ñ´æÔÚÀ´Åжϡ£
### »·¾³ÅжÏ
#### IsConsole
```csharp
public static Boolean IsConsole { get; set; }
```
ÊÇ·ñ¿ØÖÆÌ¨Ó¦ÓóÌÐò¡£
**ÅжÏÂß¼**£º
1. ³¢ÊÔ·ÃÎÊ `Console.ForegroundColor` ´¥·¢¿ØÖÆÌ¨¿ÉÓÃÐÔ¼ì²é
2. ¼ì²éµ±Ç°½ø³ÌÊÇ·ñÓÐÖ÷´°¿Ú¾ä±ú
3. ÈκÎÒì³£¶¼ÊÓΪ·Ç¿ØÖÆÌ¨»·¾³
**ʾÀý**£º
```csharp
if (Runtime.IsConsole)
{
Console.WriteLine("ÕâÊÇ¿ØÖÆÌ¨Ó¦Ó㬿ÉÒÔʹÓòÊÉ«Êä³ö");
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("ÂÌÉ«Îı¾");
Console.ResetColor();
}
else
{
// GUI Ó¦Óûò·þÎñ
Debug.WriteLine("·Ç¿ØÖÆÌ¨»·¾³");
}
```
> **×¢Òâ**£º¿ÉÒÔͨ¹ýÉèÖà `Runtime.IsConsole = false` Ç¿ÖÆ½ûÓÿØÖÆÌ¨Åжϡ£
#### Container
```csharp
public static Boolean Container { get; }
```
ÊÇ·ñÔÚ Docker/Kubernetes ÈÝÆ÷ÖÐÔËÐС£Í¨¹ý¼ì²é»·¾³±äÁ¿ `DOTNET_RUNNING_IN_CONTAINER` À´Åжϡ£
**ʾÀý**£º
```csharp
if (Runtime.Container)
{
// ÈÝÆ÷»·¾³ÏµÄÌØÊâ´¦Àí
// ÀýÈ磺ʹÓÃÈÝÆ÷ÄÚµÄÅäÖ÷¾¶
var configPath = "/app/config";
}
```
#### IsWeb
```csharp
public static Boolean IsWeb { get; }
```
ÊÇ·ñ Web Ó¦ÓóÌÐò¡£
**ÅжÏÂß¼**£º
- .NET Core/.NET 5+£º¼ì²éÊÇ·ñ¼ÓÔØÁË `Microsoft.AspNetCore` ³ÌÐò¼¯
- .NET Framework£º¼ì²é `System.Web.HttpRuntime.AppDomainAppId` ÊÇ·ñÓÐÖµ
**ʾÀý**£º
```csharp
if (Runtime.IsWeb)
{
// Web Ó¦ÓÃÌØÓеĴ¦Àí
// ÀýÈ磺ʹÓà HTTP ÉÏÏÂÎÄÏà¹Ø¹¦ÄÜ
}
```
### ʱ¼äÓë¼ÆÊý
#### TickCount64
```csharp
public static Int64 TickCount64 { get; }
```
ϵͳÆô¶¯ÒÔÀ´µÄºÁÃëÊý£¨64룩£¬²»»á·¢Éú 32 λÒç³öÎÊÌâ¡£
**ʵÏÖ·½Ê½**£º
- .NET Core 3.1+£ºÖ±½ÓʹÓà `Environment.TickCount64`
- Windows ¾É¿ò¼Ü£ºµ÷Óà `GetTickCount64` Win32 API
- ÆäËûƽ̨£ºÊ¹Óà `Stopwatch.GetTimestamp()` ¼ÆË㣬»ò»ØÍ˵½ `Environment.TickCount`
**Ó¦Óó¡¾°**£º
- ¸ß¾«¶È¼ÆÊ±
- ¼ÆËãʱ¼ä¼ä¸ô
- ±ÜÃâ `Environment.TickCount` Ô¼ 49.7 ÌìÒç³öµÄÎÊÌâ
**ʾÀý**£º
```csharp
// ²âÁ¿²Ù×÷ºÄʱ
var start = Runtime.TickCount64;
DoSomeWork();
var elapsed = Runtime.TickCount64 - start;
Console.WriteLine($"ºÄʱ: {elapsed} ms");
// ÉèÖó¬Ê±
var timeout = Runtime.TickCount64 + 5000; // 5Ãëºó³¬Ê±
while (Runtime.TickCount64 < timeout)
{
if (CheckCondition()) break;
Thread.Sleep(100);
}
```
#### UtcNow
```csharp
public static DateTimeOffset UtcNow { get; }
```
»ñÈ¡µ±Ç° UTC ʱ¼ä¡£»ùÓÚÈ«¾Öʱ¼äÌṩÕߣ¨`TimerScheduler.GlobalTimeProvider`£©£¬ÔÚÐdz¾Ó¦ÓÃÖлáÆÁ±Î·þÎñÆ÷ʱ¼ä²î¡£
**ʾÀý**£º
```csharp
var utcNow = Runtime.UtcNow;
Console.WriteLine($"UTCʱ¼ä: {utcNow}");
Console.WriteLine($"±¾µØÊ±¼ä: {utcNow.LocalDateTime}");
```
### ½ø³ÌÐÅÏ¢
#### ProcessId
```csharp
public static Int32 ProcessId { get; }
```
µ±Ç°½ø³Ì ID¡£Ê¹Óûº´æ±ÜÃâÖØ¸´»ñÈ¡¡£
**ʵÏÖ·½Ê½**£º
- .NET 5+£ºÊ¹Óà `Environment.ProcessId`
- ¾É¿ò¼Ü£ºÊ¹Óà `Process.GetCurrentProcess().Id`
**ʾÀý**£º
```csharp
Console.WriteLine($"µ±Ç°½ø³ÌID: {Runtime.ProcessId}");
// ÓÃÓÚÈÕÖ¾¼Ç¼
var logPrefix = $"[PID:{Runtime.ProcessId}]";
```
#### ClientId
```csharp
public static String ClientId { get; }
```
¿Í»§¶Ë±êʶ£¬¸ñʽΪ `ip@pid`¡£ÓÃÓÚ·Ö²¼Ê½ÏµÍ³Öбêʶ¿Í»§¶ËʵÀý¡£
**ʾÀý**£º
```csharp
Console.WriteLine($"¿Í»§¶Ë±êʶ: {Runtime.ClientId}");
// Êä³öÀàËÆ: 192.168.1.100@12345
// ÓÃÓÚ·Ö²¼Ê½Ëø¡¢ÏûÏ¢¶ÓÁÐÏû·ÑÕß±êʶµÈ
var consumerId = Runtime.ClientId;
```
### »·¾³±äÁ¿
#### GetEnvironmentVariable
```csharp
public static String? GetEnvironmentVariable(String variable)
```
»ñÈ¡»·¾³±äÁ¿£¬**²»Çø·Ö´óСд**¡£
**ÌØµã**£º
- Ïȳ¢ÊÔ¾«È·Æ¥Åä
- ÈôδÕÒµ½£¬±éÀúËùÓл·¾³±äÁ¿½øÐв»Çø·Ö´óСдµÄ±È½Ï
**ʾÀý**£º
```csharp
// ²»Çø·Ö´óСд»ñÈ¡»·¾³±äÁ¿
var path = Runtime.GetEnvironmentVariable("PATH");
var home = Runtime.GetEnvironmentVariable("HOME");
var customVar = Runtime.GetEnvironmentVariable("MY_APP_CONFIG");
```
#### GetEnvironmentVariables
```csharp
public static IDictionary<String, String?> GetEnvironmentVariables()
```
»ñÈ¡ËùÓл·¾³±äÁ¿£¬·µ»Ø²»Çø·Ö´óСдµÄ×ֵ䡣
**ʾÀý**£º
```csharp
var envVars = Runtime.GetEnvironmentVariables();
foreach (var kv in envVars.Where(e => e.Key.StartsWith("DOTNET")))
{
Console.WriteLine($"{kv.Key} = {kv.Value}");
}
```
### ÅäÖÃ
#### CreateConfigOnMissing
```csharp
public static Boolean CreateConfigOnMissing { get; set; }
```
ÅäÖÃÎļþ²»´æÔÚʱ£¬ÊÇ·ñÉú³ÉĬÈÏÅäÖÃÎļþ¡£Ä¬ÈÏΪ `true`¡£
**ÅäÖ÷½Ê½**£º
- »·¾³±äÁ¿£º`CreateConfigOnMissing=false`
- ´úÂëÉèÖãº`Runtime.CreateConfigOnMissing = false`
**ʾÀý**£º
```csharp
// Éú²ú»·¾³½ûÖ¹×Ô¶¯´´½¨ÅäÖÃÎļþ
Runtime.CreateConfigOnMissing = false;
```
### ÄÚ´æ¹ÜÀí
#### FreeMemory
```csharp
public static Boolean FreeMemory(Int32 processId = 0, Boolean gc = true, Boolean workingSet = true)
```
ÊÍ·ÅÄÚ´æ¡£Ö´ÐÐ GC »ØÊÕ²¢Êͷʤ×÷¼¯£¨Windows£©¡£
**²ÎÊý˵Ã÷**£º
- `processId`£ºÄ¿±ê½ø³ÌID£¬0 ±íʾµ±Ç°½ø³Ì
- `gc`£ºÊÇ·ñÖ´ÐÐ GC »ØÊÕ£¨½öµ±Ç°½ø³ÌÓÐЧ£©
- `workingSet`£ºÊÇ·ñÊͷʤ×÷¼¯£¨½ö Windows ÓÐЧ£©
**Ö´Ðв½Öè**£º
1. Ö´ÐÐ `GC.Collect` ½øÐÐÀ¬»ø»ØÊÕ
2. µ÷Óà `GC.WaitForPendingFinalizers` µÈ´ýÖÕ½áÆ÷
3. ÔÙ´ÎÖ´ÐÐ `GC.Collect`
4. µ÷Óà `EmptyWorkingSet` Êͷʤ×÷¼¯£¨Windows£©
**ʾÀý**£º
```csharp
// ¶¨ÆÚÊÍ·ÅÄÚ´æ
var timer = new TimerX(state =>
{
Runtime.FreeMemory();
}, null, 60_000, 60_000); // ÿ·ÖÖÓÖ´ÐÐÒ»´Î
// ½öÊͷʤ×÷¼¯£¬²»´¥·¢GC
Runtime.FreeMemory(gc: false);
// ÊÍ·ÅÖ¸¶¨½ø³ÌµÄÄÚ´æ
Runtime.FreeMemory(processId: 1234, gc: false);
```
> **×¢Òâ**£ºÆµ·±µ÷Óà `FreeMemory` ¿ÉÄÜÓ°ÏìÐÔÄÜ£¬½¨ÒéÔÚÄÚ´æÑ¹Á¦½Ï´óʱ¶¨ÆÚµ÷Óá£
## ʹÓó¡¾°
### 1. ¿çƽ̨·¾¶´¦Àí
```csharp
public String GetConfigPath()
{
if (Runtime.Windows)
return @"C:\ProgramData\MyApp\config.json";
else if (Runtime.Linux)
return "/etc/myapp/config.json";
else if (Runtime.OSX)
return "/Library/Application Support/MyApp/config.json";
else
return "config.json";
}
```
### 2. ÈÝÆ÷»·¾³ÊÊÅä
```csharp
public void ConfigureServices()
{
if (Runtime.Container)
{
// ÈÝÆ÷»·¾³£º´Ó»·¾³±äÁ¿¶ÁÈ¡ÅäÖÃ
var connStr = Runtime.GetEnvironmentVariable("DATABASE_URL");
services.AddDbContext<MyDbContext>(options =>
options.UseNpgsql(connStr));
}
else
{
// ±¾µØ¿ª·¢£º´ÓÅäÖÃÎļþ¶ÁÈ¡
var connStr = Configuration.GetConnectionString("Default");
services.AddDbContext<MyDbContext>(options =>
options.UseNpgsql(connStr));
}
}
```
### 3. ÄÚ´æ¼à¿ØÓëÊÍ·Å
```csharp
public class MemoryMonitor
{
private readonly Timer _timer;
private const Int64 MemoryThreshold = 500 * 1024 * 1024; // 500MB
public MemoryMonitor()
{
_timer = new Timer(CheckMemory, null, 0, 30_000);
}
private void CheckMemory(Object? state)
{
var gcMemory = GC.GetTotalMemory(false);
if (gcMemory > MemoryThreshold)
{
XTrace.WriteLine($"Äڴ泬¹ýãÐÖµ ({gcMemory / 1024 / 1024}MB)£¬¿ªÊ¼ÊÍ·Å");
Runtime.FreeMemory();
}
}
}
```
### 4. ÐÔÄܼÆÊ±Æ÷
```csharp
public class PerformanceTimer : IDisposable
{
private readonly String _operation;
private readonly Int64 _startTime;
public PerformanceTimer(String operation)
{
_operation = operation;
_startTime = Runtime.TickCount64;
}
public void Dispose()
{
var elapsed = Runtime.TickCount64 - _startTime;
XTrace.WriteLine($"{_operation} ºÄʱ: {elapsed}ms");
}
}
// ʹÓÃ
using (new PerformanceTimer("Êý¾Ý¿â²éѯ"))
{
var result = db.Query<User>().ToList();
}
```
## ×î¼Ñʵ¼ù
### 1. Æ½Ì¨ÌØ¶¨´úÂë¸ôÀë
```csharp
// ÍÆ¼ö£ºÊ¹ÓÃÌõ¼þÅжϸôÀëÆ½Ì¨ÌØ¶¨´úÂë
public void DoWork()
{
if (Runtime.Windows)
DoWorkWindows();
else if (Runtime.Linux)
DoWorkLinux();
else
DoWorkDefault();
}
```
### 2. ±ÜÃâÆµ·±µ÷Óà FreeMemory
```csharp
// ²»ÍƼö£ºÃ¿´Î²Ù×÷ºó¶¼ÊÍ·Å
foreach (var item in items)
{
ProcessItem(item);
Runtime.FreeMemory(); // ÐÔÄÜɱÊÖ£¡
}
// ÍÆ¼ö£ºÅúÁ¿´¦ÀíºóÊÍ·Å£¬»ò¶¨Ê±ÊÍ·Å
foreach (var item in items)
{
ProcessItem(item);
}
Runtime.FreeMemory(); // ´¦ÀíÍê³ÉºóͳһÊÍ·Å
```
### 3. ʹÓà TickCount64 ¶ø·Ç DateTime ¼ÆÊ±
```csharp
// ²»ÍƼö£ºDateTime ¼ÆÊ±¿ÉÄÜÊÜϵͳʱ¼äµ÷ÕûÓ°Ïì
var start = DateTime.Now;
DoWork();
var elapsed = (DateTime.Now - start).TotalMilliseconds;
// ÍÆ¼ö£ºTickCount64 ²»ÊÜϵͳʱ¼äÓ°Ïì
var start = Runtime.TickCount64;
DoWork();
var elapsed = Runtime.TickCount64 - start;
```
## Ïà¹ØÁ´½Ó
- [»úÆ÷ÐÅÏ¢ MachineInfo](/NewLife/X/Blob/dev/Doc/machine_info-»úÆ÷ÐÅÏ¢MachineInfo.md)
- [ÈÕ־ϵͳ ILog](/NewLife/X/Blob/dev/Doc/log-ÈÕÖ¾ILog.md)
- [¸ß¼¶¶¨Ê±Æ÷ TimerX](/NewLife/X/Blob/dev/Doc/timerx-¸ß¼¶¶¨Ê±Æ÷TimerX.md)
|