异步文件IO的应用
2007-10-30 00:05 莫耶 阅读(628) 评论(1) 编辑 收藏 举报
最近项目中大量运用xml和静态页来做缓存碎片,好处嘛有二:
1、文件碎片的过期比较灵活,不由计划任务调度,而是由访客决定何时过期,这样冷门页面自然就不用劳系统的神进行更新;
2、较之静态页,采用缓存文件碎片+动态页方式,能更加灵活地实现功能的控制,诸如一些小功能的更改。
但经过压力测试,发现同步的文件I/O,在并发过大的情况下,经常会出现锁文件的异常,颇让人头疼
只有借助异步I/O来解决了,在网上找来了一个功能较完备的工具集代码族,如下:
这里稍进行了一点改动,将标识ID(即userToken)改为了long型,在页面级别应用时,可直接将一个时间Ticks塞入以进行标识,如果这还不够,那就相当寸了,但也不坏,至少能读出东西来
据MSDN的说法,要应用异步IO功能,必须将Page的异步模式开关打开,即在页头这样写 <%@ Page sync="true"...,然后,异步代码族的调用必须在OnPreRender(EventArgs e)事件之前(含)调用,那么就可以这么写:
1、文件碎片的过期比较灵活,不由计划任务调度,而是由访客决定何时过期,这样冷门页面自然就不用劳系统的神进行更新;
2、较之静态页,采用缓存文件碎片+动态页方式,能更加灵活地实现功能的控制,诸如一些小功能的更改。
但经过压力测试,发现同步的文件I/O,在并发过大的情况下,经常会出现锁文件的异常,颇让人头疼
只有借助异步I/O来解决了,在网上找来了一个功能较完备的工具集代码族,如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
using System.ComponentModel;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
namespace IndieFacade
{
/// <summary>
/// 异步完成事件
/// </summary>
public class ReadLargeFileCompletedEventArgs : AsyncCompletedEventArgs
{
byte[] _buffer;
public byte[] Buffer
{
get { return _buffer; }
}
public ReadLargeFileCompletedEventArgs(byte[] buffer, Exception e, bool canncel, object state)
: base(e, canncel, state)
{
_buffer = buffer;
}
}
/// <summary>
/// 异步执行进度
/// </summary>
public class ReadLargeFileProgressEventArgs : ProgressChangedEventArgs
{
int _FileLen;
int _Reads;
byte[] buffer;
public ReadLargeFileProgressEventArgs(int iFileLength, int iHasRead, int Percentage, object state, byte[] _Buffer)
:
base(Percentage, state)
{
_FileLen = iFileLength;
_Reads = iHasRead;
buffer = _Buffer;
}
public int FileLength
{
get { return _FileLen; }
}
public int HasRead
{
get { return _Reads; }
}
public byte[] Buffer
{
get { return buffer; }
}
}
/// <summary>
/// 读取完成完成
/// </summary>
public delegate void ReadLargeFileCompletedEventHander(object sender, ReadLargeFileCompletedEventArgs e);
/// <summary>
/// 进度改变
/// </summary>
public delegate void ReadLargeFileProgressEventHandler(object sender, ReadLargeFileProgressEventArgs e);
/// <summary>
/// 异步数据访问
/// </summary>
public class AsyncDataAccess
{
internal delegate void WorkerEventHander(string sFilePath, object userToken);
public event ReadLargeFileCompletedEventHander ReadCompleted;
public event ReadLargeFileProgressEventHandler ReadProgressChanged;
HybridDictionary taskToker = new HybridDictionary();
SendOrPostCallback _complated;
SendOrPostCallback _reportProgress;
SendOrPostCallback _completionMethod;
protected void OnReadCompleted(ReadLargeFileCompletedEventArgs args)
{
if (ReadCompleted != null)
ReadCompleted(this, args);
}
protected void OnReadProgressChanged(ReadLargeFileProgressEventArgs args)
{
if (ReadProgressChanged != null)
ReadProgressChanged(this, args);
}
public AsyncDataAccess()
{
_complated = new SendOrPostCallback(comleted);
_reportProgress = new SendOrPostCallback(report);
_completionMethod = new SendOrPostCallback(completionMethod);
}
void comleted(object state)
{
ReadLargeFileCompletedEventArgs args = state as ReadLargeFileCompletedEventArgs;
OnReadCompleted(args);
}
void report(object state)
{
ReadLargeFileProgressEventArgs args = state as ReadLargeFileProgressEventArgs;
OnReadProgressChanged(args);
}
void completionMethod(object state)
{
AsyncDataAccessState ad = (AsyncDataAccessState)state;
AsyncOperation asyncOp = ad.AsyncOp;
ReadLargeFileCompletedEventArgs a = new ReadLargeFileCompletedEventArgs(ad.FileContent, null, false, ad.TaskID);
lock (taskToker.SyncRoot)
{
taskToker.Remove(asyncOp.UserSuppliedState);
}
asyncOp.PostOperationCompleted(_complated, a);
}
public void ReadLargeFile(string sFilePath, long iTaskID)
{
WorkerEventHander weh = new WorkerEventHander(read);
AsyncOperation op = AsyncOperationManager.CreateOperation(iTaskID);
lock (taskToker.SyncRoot)
{
if (!taskToker.Contains(iTaskID))
{
taskToker.Add(iTaskID, op);
FileInfo fi = new FileInfo(sFilePath);
AsyncDataAccessState dast = new AsyncDataAccessState(op, iTaskID, (int)fi.Length, weh, new byte[(int)fi.Length]);
采用回调方式的做法
不采用回调方式时的做法
}
}
}
void callback(IAsyncResult ar)
{
AsyncDataAccessState state = (AsyncDataAccessState)ar.AsyncState;
WorkerEventHander weh = state.Worker;
weh.EndInvoke(ar);
ReadLargeFileCompletedEventArgs args = new ReadLargeFileCompletedEventArgs(state.FileContent, null, false, state.TaskID);
_complated(args);
}
public void CancelAsync(int taskId)
{
lock (taskToker.SyncRoot)
{
object obj = taskToker[taskId];
if (obj != null)
{
AsyncOperation asyncOp = obj as AsyncOperation;
ReadLargeFileCompletedEventArgs args = new ReadLargeFileCompletedEventArgs(
null, null, true, taskId);
_complated(args);
}
}
}
private void read(string sFilepath, object userToken)
{
AsyncDataAccessState st = (AsyncDataAccessState)userToken;
FileStream fs = new FileStream(sFilepath, FileMode.Open, FileAccess.Read, FileShare.Read, 0x1000, true);
byte[] buffer = new byte[0x1000];
int res = fs.Read(buffer, 0, 0x1000);
int cnt = 0;
while (res > 0)
{
cnt += res;
byte[] cf = new byte[res];
for (int i = 0; i < res; i++)
cf[i] = buffer[i];
//lock (st.FileContent.SyncRoot)
//{
cf.CopyTo(st.FileContent, 0);
//}
int pctn = (int)((float)cnt / (float)st.FileLen * 100);
ReadLargeFileProgressEventArgs args = new ReadLargeFileProgressEventArgs(st.FileLen, cnt, pctn, st.TaskID, cf);
//Console.WriteLine("read" + cnt.ToString());
this._reportProgress(args);//-----------A
异步发送ChangedEvent,不保证发送的顺序,与A点是互斥的
res = fs.Read(buffer, 0, 0x1000);
}
fs.Close();
不采用回调方式时的做法
}
/// <summary>
/// 异步数据访问状态类
/// </summary>
internal class AsyncDataAccessState
{
public AsyncOperation AsyncOp;
public long TaskID;
public int FileLen;
public WorkerEventHander Worker;
public Byte[] FileContent;
public AsyncDataAccessState(AsyncOperation op, long iTaskID, int iFileLen, WorkerEventHander workerDelete, Byte[] _FileContent)
{
FileContent = _FileContent;
AsyncOp = op;
TaskID = iTaskID;
FileLen = iFileLen;
Worker = workerDelete;
}
}
}
}
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
using System.ComponentModel;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
namespace IndieFacade
{
/// <summary>
/// 异步完成事件
/// </summary>
public class ReadLargeFileCompletedEventArgs : AsyncCompletedEventArgs
{
byte[] _buffer;
public byte[] Buffer
{
get { return _buffer; }
}
public ReadLargeFileCompletedEventArgs(byte[] buffer, Exception e, bool canncel, object state)
: base(e, canncel, state)
{
_buffer = buffer;
}
}
/// <summary>
/// 异步执行进度
/// </summary>
public class ReadLargeFileProgressEventArgs : ProgressChangedEventArgs
{
int _FileLen;
int _Reads;
byte[] buffer;
public ReadLargeFileProgressEventArgs(int iFileLength, int iHasRead, int Percentage, object state, byte[] _Buffer)
:
base(Percentage, state)
{
_FileLen = iFileLength;
_Reads = iHasRead;
buffer = _Buffer;
}
public int FileLength
{
get { return _FileLen; }
}
public int HasRead
{
get { return _Reads; }
}
public byte[] Buffer
{
get { return buffer; }
}
}
/// <summary>
/// 读取完成完成
/// </summary>
public delegate void ReadLargeFileCompletedEventHander(object sender, ReadLargeFileCompletedEventArgs e);
/// <summary>
/// 进度改变
/// </summary>
public delegate void ReadLargeFileProgressEventHandler(object sender, ReadLargeFileProgressEventArgs e);
/// <summary>
/// 异步数据访问
/// </summary>
public class AsyncDataAccess
{
internal delegate void WorkerEventHander(string sFilePath, object userToken);
public event ReadLargeFileCompletedEventHander ReadCompleted;
public event ReadLargeFileProgressEventHandler ReadProgressChanged;
HybridDictionary taskToker = new HybridDictionary();
SendOrPostCallback _complated;
SendOrPostCallback _reportProgress;
SendOrPostCallback _completionMethod;
protected void OnReadCompleted(ReadLargeFileCompletedEventArgs args)
{
if (ReadCompleted != null)
ReadCompleted(this, args);
}
protected void OnReadProgressChanged(ReadLargeFileProgressEventArgs args)
{
if (ReadProgressChanged != null)
ReadProgressChanged(this, args);
}
public AsyncDataAccess()
{
_complated = new SendOrPostCallback(comleted);
_reportProgress = new SendOrPostCallback(report);
_completionMethod = new SendOrPostCallback(completionMethod);
}
void comleted(object state)
{
ReadLargeFileCompletedEventArgs args = state as ReadLargeFileCompletedEventArgs;
OnReadCompleted(args);
}
void report(object state)
{
ReadLargeFileProgressEventArgs args = state as ReadLargeFileProgressEventArgs;
OnReadProgressChanged(args);
}
void completionMethod(object state)
{
AsyncDataAccessState ad = (AsyncDataAccessState)state;
AsyncOperation asyncOp = ad.AsyncOp;
ReadLargeFileCompletedEventArgs a = new ReadLargeFileCompletedEventArgs(ad.FileContent, null, false, ad.TaskID);
lock (taskToker.SyncRoot)
{
taskToker.Remove(asyncOp.UserSuppliedState);
}
asyncOp.PostOperationCompleted(_complated, a);
}
public void ReadLargeFile(string sFilePath, long iTaskID)
{
WorkerEventHander weh = new WorkerEventHander(read);
AsyncOperation op = AsyncOperationManager.CreateOperation(iTaskID);
lock (taskToker.SyncRoot)
{
if (!taskToker.Contains(iTaskID))
{
taskToker.Add(iTaskID, op);
FileInfo fi = new FileInfo(sFilePath);
AsyncDataAccessState dast = new AsyncDataAccessState(op, iTaskID, (int)fi.Length, weh, new byte[(int)fi.Length]);
采用回调方式的做法
不采用回调方式时的做法
}
}
}
void callback(IAsyncResult ar)
{
AsyncDataAccessState state = (AsyncDataAccessState)ar.AsyncState;
WorkerEventHander weh = state.Worker;
weh.EndInvoke(ar);
ReadLargeFileCompletedEventArgs args = new ReadLargeFileCompletedEventArgs(state.FileContent, null, false, state.TaskID);
_complated(args);
}
public void CancelAsync(int taskId)
{
lock (taskToker.SyncRoot)
{
object obj = taskToker[taskId];
if (obj != null)
{
AsyncOperation asyncOp = obj as AsyncOperation;
ReadLargeFileCompletedEventArgs args = new ReadLargeFileCompletedEventArgs(
null, null, true, taskId);
_complated(args);
}
}
}
private void read(string sFilepath, object userToken)
{
AsyncDataAccessState st = (AsyncDataAccessState)userToken;
FileStream fs = new FileStream(sFilepath, FileMode.Open, FileAccess.Read, FileShare.Read, 0x1000, true);
byte[] buffer = new byte[0x1000];
int res = fs.Read(buffer, 0, 0x1000);
int cnt = 0;
while (res > 0)
{
cnt += res;
byte[] cf = new byte[res];
for (int i = 0; i < res; i++)
cf[i] = buffer[i];
//lock (st.FileContent.SyncRoot)
//{
cf.CopyTo(st.FileContent, 0);
//}
int pctn = (int)((float)cnt / (float)st.FileLen * 100);
ReadLargeFileProgressEventArgs args = new ReadLargeFileProgressEventArgs(st.FileLen, cnt, pctn, st.TaskID, cf);
//Console.WriteLine("read" + cnt.ToString());
this._reportProgress(args);//-----------A
异步发送ChangedEvent,不保证发送的顺序,与A点是互斥的
res = fs.Read(buffer, 0, 0x1000);
}
fs.Close();
不采用回调方式时的做法
}
/// <summary>
/// 异步数据访问状态类
/// </summary>
internal class AsyncDataAccessState
{
public AsyncOperation AsyncOp;
public long TaskID;
public int FileLen;
public WorkerEventHander Worker;
public Byte[] FileContent;
public AsyncDataAccessState(AsyncOperation op, long iTaskID, int iFileLen, WorkerEventHander workerDelete, Byte[] _FileContent)
{
FileContent = _FileContent;
AsyncOp = op;
TaskID = iTaskID;
FileLen = iFileLen;
Worker = workerDelete;
}
}
}
}
这里稍进行了一点改动,将标识ID(即userToken)改为了long型,在页面级别应用时,可直接将一个时间Ticks塞入以进行标识,如果这还不够,那就相当寸了,但也不坏,至少能读出东西来
据MSDN的说法,要应用异步IO功能,必须将Page的异步模式开关打开,即在页头这样写 <%@ Page sync="true"...,然后,异步代码族的调用必须在OnPreRender(EventArgs e)事件之前(含)调用,那么就可以这么写:
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
// 功能处理
if (Request.QueryString["id"] == null)
return;
// 传递的艺人ID
this.artId = Convert.ToInt32(Request.QueryString["id"]);
// 获取信息
GenStaticHtml();
}
// --------------------------- 生成方法 ------------------------------- //
/// <summary>
/// 生成静态页
/// </summary>
void GenStaticHtml()
// --------------------------- 异步事件 ------------------------------- //
protected void da_ReadCompleted(object sender, ReadLargeFileCompletedEventArgs e)
{
long id = (long)e.UserState;
if (id == tid)
{
Response.Write(Encoding.UTF8.GetString(e.Buffer, 0, e.Buffer.Length));
Response.Flush();
Response.End();
}
}
{
base.OnPreRender(e);
// 功能处理
if (Request.QueryString["id"] == null)
return;
// 传递的艺人ID
this.artId = Convert.ToInt32(Request.QueryString["id"]);
// 获取信息
GenStaticHtml();
}
// --------------------------- 生成方法 ------------------------------- //
/// <summary>
/// 生成静态页
/// </summary>
void GenStaticHtml()
// --------------------------- 异步事件 ------------------------------- //
protected void da_ReadCompleted(object sender, ReadLargeFileCompletedEventArgs e)
{
long id = (long)e.UserState;
if (id == tid)
{
Response.Write(Encoding.UTF8.GetString(e.Buffer, 0, e.Buffer.Length));
Response.Flush();
Response.End();
}
}
本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 Unported许可协议
欢迎转载,但必须保留文章的署名老莫的帐本子
并保留此链接:http://moye.cnblogs.com/
如有疑问请发邮件:moyerock@gmail.com
欢迎转载,但必须保留文章的署名老莫的帐本子
并保留此链接:http://moye.cnblogs.com/
如有疑问请发邮件:moyerock@gmail.com