-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
What's new in .NET 7 Preview 4 [WIP] #7378
Comments
ObservabilityIntroducing Activity.Current change event dotnet/runtime#67276 public partial class Activity : IDisposable
{
public static event EventHandler<ActivityChangedEventArgs>? CurrentChanged;
} Usage Example Activity.CurrentChanged += CurrentChanged;
void CurrentChanged(object? sender, ActivityChangedEventArgs e)
{
Console.WriteLine($"Activity.Current value changed from Activity: {e.Previous.OperationName} to Activity: {e.Current.OperationName}");
} Expose performant Activity properties enumerator methods dotnet/runtime#67207The exposed methods can be used in the perf critical scenarios to enumerate the Activity Tags, Links, and Events properties without any extra allocations and with fast items access. namespace System.Diagnostics
{
partial class Activity
{
public Enumerator<KeyValuePair<string,object>> EnumerateTagObjects();
public Enumerator<ActivityLink> EnumerateLinks();
public Enumerator<ActivityEvent> EnumerateEvents();
public struct Enumerator<T>
{
public readonly Enumerator<T> GetEnumerator();
public readonly ref T Current;
public bool MoveNext();
}
}
} Usage Example Activity a = new Activity("Root");
a.SetTag("key1", "value1");
a.SetTag("key2", "value2");
foreach (ref readonly KeyValuePair<string, object?> tag in a.EnumerateTagObjects())
{
Console.WriteLine($"{tag.Key}, {tag.Value}");
} |
Adding Microseconds and Nanoseconds to TimeStamp, DateTime, DateTimeOffset, and TimeOnly dotnet/runtime#23799namespace System {
public struct DateTime {
public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond);
public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, System.DateTimeKind kind);
public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, System.Globalization.Calendar calendar);
public int Microsecond { get; }
public int Nanosecond { get; }
public DateTime AddMicroseconds(double value);
}
public struct DateTimeOffset {
public DateTimeOffset(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, System.TimeSpan offset);
public DateTimeOffset(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, System.TimeSpan offset, System.Globalization.Calendar calendar);
public int Microsecond { get; }
public int Nanosecond { get; }
public DateTimeOffset AddMicroseconds(double microseconds);
}
public struct TimeSpan {
public const long TicksPerMicrosecond = 10L;
public const long NanosecondsPerTick = 100L;
public TimeSpan(int days, int hours, int minutes, int seconds, int milliseconds, int microseconds);
public int Microseconds { get; }
public int Nanoseconds { get; }
public double TotalMicroseconds { get; }
public double TotalNanoseconds { get; }
public static TimeSpan FromMicroseconds(double microseconds);
}
public struct TimeOnly {
public TimeOnly(int day, int hour, int minute, int second, int millisecond, int microsecond);
public int Microsecond { get; }
public int Nanosecond { get; }
}
} Thanks to @ChristopherHaws and @deeprobin helping in the design and implementation. |
More improvements and new APIs for System.Text.RegularExpressionsAugment Regex extensibility point for better perf and span-based matching For preview 4 we are adding the remaining planned APIs in order to add span support into our Regex library. These APIs are amortized allocation-free. The main span-based APIs being added for Preview 4 are:
We have also done a lot of work that enhances Regex performance in general, with improvements like:
Finally we have also made some improvements on the code that is generated by the Regex source generator in order to make the code more readable and easier to debug, as well as enable projects with multiple source generated regex patterns to share common code between them. |
Added metrics for
|
.NET Libraries: Nullable annotations for Microsoft.ExtensionsWe have finished annotating the Microsoft.Extensions.* libraries for nullability. In .NET 7 Preview 4, all Microsoft.Extensions.* libraries have been fully annotated for nullability. This work wouldn't have been possible without @maxkoshevoi's multiple-month effort. Starting with the first PR in August 2021, all the way to the final PR in April 2022, this was a lot of work that is greatly appreciated by the .NET community. |
Adding new Tar APIsImplement Tar APIs - dotnet/runtime#67883 We are adding the new Usage examplesFor the most common usage, extracting and archiving, we are offering these methods: // Generates a tar archive where all the entry names are prefixed by the root directory 'SourceDirectory'
TarFile.CreateFromDirectory(sourceDirectoryName: "/home/dotnet/SourceDirectory/", destinationFileName: "/home/dotnet/destination.tar", includeBaseDirectory: true);
// Extracts the contents of a tar archive into the specified directory, but avoids overwriting anything found inside
TarFile.ExtractToDirectory(sourceFileName: "/home/dotnet/destination.tar", destinationDirectoryName: "/home/dotnet/DestinationDirectory/", overwriteFiles: false); We also offer variants that allow extracting from a stream or archiving into a stream: // Generates a tar archive where all the entry names are prefixed by the root directory 'SourceDirectory'
using MemoryStream archiveStream = new();
TarFile.CreateFromDirectory(sourceDirectoryName: @"D:\SourceDirectory\", destination: archiveStream, includeBaseDirectory: true);
// Extracts the contents of a stream tar archive into the specified directory, and avoids overwriting anything found inside
TarFile.ExtractToDirectory(source: archiveStream, destinationDirectoryName: @"D:\DestinationDirectory\", overwriteFiles: false); Additionally, the entries of an archive can be traversed one by one using the reader: // Opens an archive for reading individual entries, and closes the archive stream after the reader disposal
using FileStream archiveStream = File.OpenRead("/home/dotnet/SourceDirectory/source.tar");
using TarReader reader = new(archiveStream, leaveOpen: false);
TarEntry? entry;
while ((entry = reader.GetNextEntry()) != null)
{
// Extracts an entry to the desired destination, and overwrites if an entry with the same name is found
string destinationFileName = Path.Join("/home/dotnet/DestinationDirectory", entry.Name);
entry.ExtractToFile(destinationFileName, overwrite: true);
} And entries can also be written one by one into an archive stream using the writer: using FileStream archiveStream = File.OpenWrite(@"D:\DestinationDirectory\destination.tar");
// Create the archive in the PAX format and write individual entries, closing the stream after the writer disposal
using TarWriter writer = new(archiveStream, TarFormat.Pax, leaveOpen: false);
// Add an entry from an existing file
writer.WriteEntry(fileName: @"D:\SourceDirectory\file.txt", entryName: "file.txt");
// Or write an entry from scratch
PaxTarEntry entry = new(entryType: TarEntryType.Directory, entryName: "directory");
writer.WriteEntry(entry); We can also pair these new APIs with stream-based compression methods, like Extracting the contents from a compressed tar archive into the filesystem: using FileStream compressedStream = File.OpenRead("/home/dotnet/SourceDirectory/compressed.tar.gz");
using GZipStream decompressor = new(compressedStream, CompressionMode.Decompress);
TarFile.ExtractToDirectory(source: decompressor, destinationDirectoryName: "/home/dotnet/DestinationDirectory/", overwriteFiles: false); Reading individual entries from a compressed tar archive: using FileStream compressedStream = File.OpenRead(@"D:\SourceDirectory\compressed.tar.gz");
using GZipStream decompressor = new(compressedStream, CompressionMode.Decompress);
using TarReader reader = new(decompressor, leaveOpen: true);
TarEntry? entry;
while ((entry = GetNextEntry(copyData: true)) != null)
{
Console.WriteLine($"Entry type: {entry.EntryType}, entry name: {entry.Name}");
} Writing the contents of a directory into a compressed tar archive: using FileStream compressedStream = File.Create("/home/dotnet/DestinationDirectory/compressed.tar.gz");
using GZipStream compressor = new(compressedStream, CompressionMode.Compress);
TarFile.CreateFromDirectory(sourceDirectoryName: "/home/dotnet/SourceDirectory/", destination: compressor, includeBaseDirectory: true); Or write individual entries into a compressed tar archive: using FileStream compressedStream = File.Create(@"D:\DestinationDirectory\compressed.tar.gz");
using (GZipStream compressor = new(compressedStream, CompressionMode.Compress))
{
using (TarWriter writer = new TarWriter(compressor, TarFormat.Pax, leaveOpen: true))
{
// Add an entry from an existing file
writer.WriteEntry(fileName: @"D:\SourceDirectory\file.txt", entryName: "file.txt");
// Or write an entry from scratch
PaxTarEntry entry = new(entryType: TarEntryType.Directory, entryName: "directory");
writer.WriteEntry(entry);
}
} APIsnamespace System.Formats.Tar
{
public static class TarFile
{
public static void CreateFromDirectory(string sourceDirectoryName, string destinationFileName, bool includeBaseDirectory);
public static void CreateFromDirectory(string sourceDirectoryName, Stream destination, bool includeBaseDirectory);
public static void ExtractToDirectory(string sourceFileName, string destinationDirectoryName, bool overwriteFiles);
public static void ExtractToDirectory(Stream source, string destinationDirectoryName, bool overwriteFiles);
}
public enum TarEntryType : byte
{
V7RegularFile = '\0',
RegularFile = '0',
HardLink = '1',
SymbolicLink = '2',
CharacterDevice = '3',
BlockDevice = '4',
Directory = '5',
Fifo = '6',
GlobalExtendedAttributes = 'g',
ExtendedAttributes = 'x',
ContiguousFile = '7',
DirectoryList = 'D',
LongLink = 'K',
LongPath = 'L',
MultiVolume = 'M',
RenamedOrSymlinked = 'N',
SparseFile = 'S',
TapeVolume = 'T',
}
public enum TarFormat
{
Unknown = 0,
V7 = 1,
Ustar = 2,
Pax = 3,
Gnu = 4,
}
public sealed class TarReader : System.IDisposable
{
public TarReader(System.IO.Stream archiveStream, bool leaveOpen = false);
public System.Formats.Tar.TarFormat Format { get; }
public System.Collections.Generic.IReadOnlyDictionary<string, string>? GlobalExtendedAttributes { get; }
public void Dispose();
public System.Formats.Tar.TarEntry? GetNextEntry(bool copyData = false);
}
public sealed class TarWriter : System.IDisposable
{
public TarWriter(System.IO.Stream archiveStream, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>>? globalExtendedAttributes = null, bool leaveOpen = false);
public TarWriter(System.IO.Stream archiveStream, System.Formats.Tar.TarFormat archiveFormat, bool leaveOpen = false);
public System.Formats.Tar.TarFormat Format { get; }
public void Dispose();
public void WriteEntry(string fileName, string? entryName);
public void WriteEntry(System.Formats.Tar.TarEntry entry);
}
public abstract class TarEntry
{
internal TarEntry();
public int Checksum { get; }
public System.IO.Stream? DataStream { get; set; }
public System.Formats.Tar.TarEntryType EntryType { get; }
public int Gid { get; set; }
public long Length { get; }
public string LinkName { get; set; }
public TarFileMode Mode { get; set; }
public System.DateTimeOffset ModificationTime { get; set; }
public string Name { get; set; }
public int Uid { get; set; }
public void ExtractToFile(string destinationFileName, bool overwrite);
public override string ToString();
}
public sealed class V7TarEntry : TarEntry
{
public V7TarEntry(System.Formats.Tar.TarEntryType entryType, string entryName);
}
public abstract class PosixTarEntry : TarEntry
{
internal PosixTarEntry();
public int DeviceMajor { get; set; }
public int DeviceMinor { get; set; }
public string GroupName { get; set; }
public string UserName { get; set; }
public override string ToString();
}
public sealed class UstarTarEntry : TarEntryPosix
{
public UstarTarEntry(System.Formats.Tar.TarEntryType entryType, string entryName);
}
public sealed class PaxTarEntry : TarEntryPosix
{
public PaxTarEntry(System.Formats.Tar.TarEntryType entryType, string entryName, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>>? extendedAttributes);
public System.Collections.Generic.IReadOnlyDictionary<string, string> ExtendedAttributes { get; }
}
public sealed class GnuTarEntry : TarEntryPosix
{
public GnuTarEntry(System.Formats.Tar.TarEntryType entryType, string entryName);
public System.DateTimeOffset AccessTime { get; set; }
public System.DateTimeOffset ChangeTime { get; set; }
}
[System.FlagsAttribute]
public enum TarFileMode
{
None = 0,
OtherExecute = 1,
OtherWrite = 2,
OtherRead = 4,
GroupExecute = 8,
GroupWrite = 16,
GroupRead = 32,
UserExecute = 64,
UserWrite = 128,
UserRead = 256,
StickyBit = 512,
GroupSpecial = 1024,
UserSpecial = 2048,
}
} Notes
|
On Stack Replacement (aka OSR)On Stack Replacement allows the runtime to change the code executed by currently running methods in the middle of method execution, while those methods are active "on stack." It serves as a complement to tiered compilation. dotnet/runtime#65675 enabled OSR by default on x64 and Arm64, and enabled quick jitting for methods with loops on those same platforms. OSR allows long-running methods to switch to more optimized versions mid-execution, so the runtime can jit all methods quickly at first and then transition to more optimized versions when those methods are called frequently (via tiered compilation) or have long-running loops (via OSR). Performance ImpactOSR improves startup time. Almost all methods are now initially jitted by the quick jit. We have seen 25% improvement in startup time in jitting-heavy applications like Avalonia “IL” spy, and the various TechEmpower benchmarks we track show 10-30% improvements in time to first request (see chart below: OSR was enabled by default on March 30). OSR can also improve performance of applications, and in particular, applications using Dynamic PGO, as methods with loops are now better optimized. For example, the Further technical detailsSee the OSR Design Document for details on how OSR works. See OSR Next Steps for details on the work that went into enabling OSR, and possible future enhancements. |
.NET 7 GA is available. Closing these pre-release issues. |
What's new in .NET 7 Preview 4
This issue is for teams to highlight work for the community that will release .NET 7 Preview 4
To add content, use a new conversation entry. The entry should include the team name and feature title as the first line as shown in the template below.
Preview 1: #7106
Preview 2: #7107
Preview 3: #7108
Preview 4: #7378
Preview 5: #7441
Preview 6: #7454
Preview 7: #7455
The text was updated successfully, but these errors were encountered: