I/O操作是指输入/输出操作,是计算机与外部设备(如硬盘、网络、用户输入设备等)之间进行数据交换的过程。I/O操作包括多种类型,涵盖了文件操作、网络通信、内存操作和控制台交互等。
同步I/O操作是指程序在执行I/O操作时必须等待操作完成才能继续执行后续的代码。同步I/O操作的优点是简单直观,易于理解和实现,但缺点是效率较低,因为程序的执行会因为等待I/O操作而被阻塞。
异步I/O操作是指程序在执行I/O操作时,可以不等待操作完成,而是继续执行后续的代码。当I/O操作完成后,系统会通过回调函数、事件通知等方式告诉程序。异步I/O操作的优点是可以提高程序的执行效率,特别是在需要处理大量I/O操作的情况下,因为程序可以在等待I/O操作完成的同时执行其他任务。异步I/O操作的方法包括但不限于:
- 回调函数:当I/O操作完成后,调用预先定义好的回调函数。
- 事件驱动:程序通过监听事件来了解I/O操作的状态。
- 信号量:通过信号量控制程序的执行流程,当I/O操作完成时,释放信号量,程序可以继续执行。
- 通知机制:例如Linux中的inotify,可以监控文件系统的变化。
- 线程和协程:使用多线程或多协程的方式,一个线程或协程负责I/O操作,其他线程或协程可以继续执行其他任务。
这些方法可以单独使用,也可以结合使用,以达到最佳的程序性能。
下面是分别使用同步和异步方式进行文件I/O和网络I/O操作的详细示例。
文件I/O操作
同步文件写入
使用StreamWriter
类进行同步文件写入操作:
using System;
using System.IO;
class SyncFileWriteExample
{
static void Main()
{
string filePath = "sync_example.txt";
string content = "这是一个同步文件写入的示例。";
// 使用 StreamWriter 同步写入文件
using (StreamWriter writer = new StreamWriter(filePath))
{
writer.WriteLine(content);
}
Console.WriteLine("同步文件写入完成。");
}
}
异步文件写入
使用StreamWriter
类进行异步文件写入操作:
using System;
using System.IO;
using System.Threading.Tasks;
class AsyncFileWriteExample
{
static async Task Main()
{
string filePath = "async_example.txt";
string content = "这是一个异步文件写入的示例。";
// 使用 StreamWriter 异步写入文件
using (StreamWriter writer = new StreamWriter(filePath))
{
await writer.WriteLineAsync(content);
}
Console.WriteLine("异步文件写入完成。");
}
}
同步文件读取
使用StreamReader
类进行同步文件读取操作:
using System;
using System.IO;
class SyncFileReadExample
{
static void Main()
{
string filePath = "sync_example.txt";
// 使用 StreamReader 同步读取文件
if (File.Exists(filePath))
{
using (StreamReader reader = new StreamReader(filePath))
{
string content = reader.ReadToEnd();
Console.WriteLine("同步读取的文件内容:");
Console.WriteLine(content);
}
}
else
{
Console.WriteLine("文件不存在。");
}
}
}
CopyInsert
异步文件读取
使用StreamReader
类进行异步文件读取操作:
using System;
using System.IO;
using System.Threading.Tasks;
class AsyncFileReadExample
{
static async Task Main()
{
string filePath = "async_example.txt";
// 使用 StreamReader 异步读取文件
if (File.Exists(filePath))
{
using (StreamReader reader = new StreamReader(filePath))
{
string content = await reader.ReadToEndAsync();
Console.WriteLine("异步读取的文件内容:");
Console.WriteLine(content);
}
}
else
{
Console.WriteLine("文件不存在。");
}
}
}
网络I/O操作
同步网络发送数据
使用TcpClient
类进行同步网络发送数据:
using System;
using System.Net.Sockets;
using System.Text;
class SyncTcpClientExample
{
static void Main()
{
TcpClient client = new TcpClient();
try
{
client.Connect("127.0.0.1", 5000);
NetworkStream stream = client.GetStream();
// 同步发送数据
string message = "Hello, Server!";
byte[] data = Encoding.ASCII.GetBytes(message);
stream.Write(data, 0, data.Length);
Console.WriteLine("同步发送消息到服务器完成。");
// 同步接收响应
data = new byte[256];
int bytesRead = stream.Read(data, 0, data.Length);
string response = Encoding.ASCII.GetString(data, 0, bytesRead);
Console.WriteLine("服务器响应: " + response);
}
catch (Exception e)
{
Console.WriteLine("异常: " + e.Message);
}
finally
{
client.Close();
}
}
}
异步网络发送数据
使用TcpClient
类进行异步网络发送数据:
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class AsyncTcpClientExample
{
static async Task Main()
{
TcpClient client = new TcpClient();
try
{
await client.ConnectAsync("127.0.0.1", 5000);
NetworkStream stream = client.GetStream();
// 异步发送数据
string message = "Hello, Server!";
byte[] data = Encoding.ASCII.GetBytes(message);
await stream.WriteAsync(data, 0, data.Length);
Console.WriteLine("异步发送消息到服务器完成。");
// 异步接收响应
data = new byte[256];
int bytesRead = await stream.ReadAsync(data, 0, data.Length);
string response = Encoding.ASCII.GetString(data, 0, bytesRead);
Console.WriteLine("服务器响应: " + response);
}
catch (Exception e)
{
Console.WriteLine("异常: " + e.Message);
}
finally
{
client.Close();
}
}
}
同步网络接收数据
使用TcpListener
类进行同步网络接收数据:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class SyncTcpServerExample
{
static void Main()
{
TcpListener server = new TcpListener(IPAddress.Any, 5000);
server.Start();
Console.WriteLine("等待客户端连接...");
// 同步接受客户端连接
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("客户端已连接。");
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[256];
int bytesRead;
// 同步从客户端接收数据
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
{
string receivedData = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine("接收到的数据: " + receivedData);
// 同步发送响应到客户端
string response = "Hello, Client!";
byte[] responseData = Encoding.ASCII.GetBytes(response);
stream.Write(responseData, 0, responseData.Length);
}
client.Close();
server.Stop();
}
}
异步网络接收数据
使用TcpListener
类进行异步网络接收数据:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class AsyncTcpServerExample
{
static async Task Main()
{
TcpListener server = new TcpListener(IPAddress.Any, 5000);
server.Start();
Console.WriteLine("等待客户端连接...");
// 异步接受客户端连接
TcpClient client = await server.AcceptTcpClientAsync();
Console.WriteLine("客户端已连接。");
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[256];
int bytesRead;
// 异步从客户端接收数据
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
string receivedData = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine("接收到的数据: " + receivedData);
// 异步发送响应到客户端
string response = "Hello, Client!";
byte[] responseData = Encoding.ASCII.GetBytes(response);
await stream.WriteAsync(responseData, 0, responseData.Length);
}
client.Close();
server.Stop();
}
}
内存I/O操作
同步内存写入
使用MemoryStream
类进行同步内存写入操作:
using System;
using System.IO;
class SyncMemoryWriteExample
{
static void Main()
{
using (MemoryStream memoryStream = new MemoryStream())
{
// 同步写入数据到内存流
string message = "这是一个同步内存写入的示例。";
byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
memoryStream.Write(data, 0, data.Length);
// 将流的位置重置到开始
memoryStream.Seek(0, SeekOrigin.Begin);
// 从内存流中读取数据
byte[] buffer = new byte[data.Length];
int bytesRead = memoryStream.Read(buffer, 0, buffer.Length);
string receivedData = System.Text.Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine("从内存流中读取的数据: " + receivedData);
}
}
}
CopyInsert
异步内存写入
使用MemoryStream
类进行异步内存写入操作:
using System;
using System.IO;
using System.Threading.Tasks;
class AsyncMemoryWriteExample
{
static async Task Main()
{
using (MemoryStream memoryStream = new MemoryStream())
{
// 异步写入数据到内存流
string message = "这是一个异步内存写入的示例。";
byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
await memoryStream.WriteAsync(data, 0, data.Length);
// 将流的位置重置到开始
memoryStream.Seek(0, SeekOrigin.Begin);
// 从内存流中读取数据
byte[] buffer = new byte[data.Length];
int bytesRead = await memoryStream.ReadAsync(buffer, 0, buffer.Length);
string receivedData = System.Text.Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine("从内存流中读取的数据: " + receivedData);
}
}
}
控制台I/O操作
同步控制台输入
使用Console.ReadLine
方法进行同步控制台输入操作:
using System;
class SyncConsoleInputExample
{
static void Main()
{
Console.WriteLine("请输入一些文本:");
string userInput = Console.ReadLine();
Console.WriteLine("你输入的文本是: " + userInput);
}
}
异步控制台输入
C#的Console
类没有直接提供异步方法来读取输入,但可以使用Task.Run
来实现异步效果:
using System;
using System.Threading.Tasks;
class AsyncConsoleInputExample
{
static async Task Main()
{
Console.WriteLine("请输入一些文本:");
Task<string> readTask = Task.Run(() => Console.ReadLine());
string userInput = await readTask;
Console.WriteLine("你输入的文本是: " + userInput);
}
}
数据库I/O操作
在C#中,数据库I/O操作通常涉及使用ADO.NET或其他ORM(对象关系映射)框架(如Entity Framework)与数据库进行交互。
- 同步数据库操作:直接调用同步方法(如
ExecuteNonQuery
、ExecuteReader
、SaveChanges
),会阻塞当前线程,直到操作完成。 - 异步数据库操作:调用异步方法(如
ExecuteNonQueryAsync
、ExecuteReaderAsync
、SaveChangesAsync
),不会阻塞当前线程,允许程序在等待数据库操作完成的同时执行其他任务。
使用 ADO.NET 进行数据库I/O操作
ADO.NET 提供了 SqlConnection
、SqlCommand
等类来与数据库进行交互。我们可以通过这些类的同步和异步方法来执行数据库操作。
同步数据库写入操作
使用 SqlCommand
进行同步数据库写入操作:
using System;
using System.Data.SqlClient;
class SyncDatabaseWriteExample
{
static void Main()
{
string connectionString = "Server=(localdb)\\mssqllocaldb;Database=TestDB;Integrated Security=True;";
string query = "INSERT INTO Users (Name, Age) VALUES (@Name, @Age)";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(query, connection))
{
command.Parameters.AddWithValue("@Name", "Alice");
command.Parameters.AddWithValue("@Age", 30);
// 同步执行插入操作
int rowsAffected = command.ExecuteNonQuery();
Console.WriteLine("同步数据库写入完成,影响的行数: " + rowsAffected);
}
}
}
}
异步数据库写入操作
使用 SqlCommand
进行异步数据库写入操作:
using System;
using System.Data.SqlClient;
using System.Threading.Tasks;
class AsyncDatabaseWriteExample
{
static async Task Main()
{
string connectionString = "Server=(localdb)\\mssqllocaldb;Database=TestDB;Integrated Security=True;";
string query = "INSERT INTO Users (Name, Age) VALUES (@Name, @Age)";
using (SqlConnection connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
using (SqlCommand command = new SqlCommand(query, connection))
{
command.Parameters.AddWithValue("@Name", "Bob");
command.Parameters.AddWithValue("@Age", 25);
// 异步执行插入操作
int rowsAffected = await command.ExecuteNonQueryAsync();
Console.WriteLine("异步数据库写入完成,影响的行数: " + rowsAffected);
}
}
}
}
同步数据库读取操作
使用 SqlCommand
进行同步数据库读取操作:
using System;
using System.Data.SqlClient;
class SyncDatabaseReadExample
{
static void Main()
{
string connectionString = "Server=(localdb)\\mssqllocaldb;Database=TestDB;Integrated Security=True;";
string query = "SELECT Name, Age FROM Users";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(query, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
// 读取数据
while (reader.Read())
{
string name = reader.GetString(0);
int age = reader.GetInt32(1);
Console.WriteLine($"同步读取的数据: Name = {name}, Age = {age}");
}
}
}
}
}
}
异步数据库读取操作
使用 SqlCommand
进行异步数据库读取操作:
using System;
using System.Data.SqlClient;
using System.Threading.Tasks;
class AsyncDatabaseReadExample
{
static async Task Main()
{
string connectionString = "Server=(localdb)\\mssqllocaldb;Database=TestDB;Integrated Security=True;";
string query = "SELECT Name, Age FROM Users";
using (SqlConnection connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
using (SqlCommand command = new SqlCommand(query, connection))
{
using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
// 异步读取数据
while (await reader.ReadAsync())
{
string name = reader.GetString(0);
int age = reader.GetInt32(1);
Console.WriteLine($"异步读取的数据: Name = {name}, Age = {age}");
}
}
}
}
}
}
使用 Entity Framework 进行数据库I/O操作
Entity Framework 是一个ORM框架,可以简化数据库操作。我们可以通过其同步和异步方法来执行数据库操作。
同步数据库写入操作
使用 Entity Framework 进行同步数据库写入操作:
using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
class SyncDatabaseWriteEFExample
{
static void Main()
{
using (var context = new TestDbContext())
{
var user = new User { Name = "Charlie", Age = 35 };
context.Users.Add(user);
// 同步保存更改
int rowsAffected = context.SaveChanges();
Console.WriteLine("同步数据库写入完成,影响的行数: " + rowsAffected);
}
}
}
public class TestDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=TestDB;Integrated Security=True;");
}
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
异步数据库写入操作
使用 Entity Framework 进行异步数据库写入操作:
using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
class AsyncDatabaseWriteEFExample
{
static async Task Main()
{
using (var context = new TestDbContext())
{
var user = new User { Name = "David", Age = 40 };
context.Users.Add(user);
// 异步保存更改
int rowsAffected = await context.SaveChangesAsync();
Console.WriteLine("异步数据库写入完成,影响的行数: " + rowsAffected);
}
}
}
public class TestDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=TestDB;Integrated Security=True;");
}
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
同步数据库读取操作
使用 Entity Framework 进行同步数据库读取操作:
using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
class SyncDatabaseReadEFExample
{
static void Main()
{
using (var context = new TestDbContext())
{
var users = context.Users.ToList();
// 读取数据
foreach (var user in users)
{
Console.WriteLine($"同步读取的数据: Id = {user.Id}, Name = {user.Name}, Age = {user.Age}");
}
}
}
}
public class TestDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=TestDB;Integrated Security=True;");
}
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
异步数据库读取操作
使用 Entity Framework 进行异步数据库读取操作:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
class AsyncDatabaseReadEFExample
{
static async Task Main()
{
using (var context = new TestDbContext())
{
var users = await context.Users.ToListAsync();
// 异步读取数据
foreach (var user in users)
{
Console.WriteLine($"异步读取的数据: Id = {user.Id}, Name = {user.Name}, Age = {user.Age}");
}
}
}
}
public class TestDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=TestDB;Integrated Security=True;");
}
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
总结
- 同步I/O操作:阻塞当前线程,直到操作完成。适用于I/O操作时间较短的情况,可以简化代码逻辑。
- 异步I/O操作:不阻塞当前线程,允许程序在等待I/O操作完成的同时执行其他任务。适用于I/O操作时间较长的情况,可以提高程序的响应性和性能。
通过这些示例,你可以看到同步和异步I/O操作在C#中的具体实现方式和差异。