从asp.net任务异步写入日志文件

时间:2016-06-05 04:01:55

标签: asp.net vb.net multithreading file

使用VB.Net(Framework 4.5.1版)

我有一个程序设置一个(System.Threading.Tasks.Task)任务列表,执行如下(只显示相关代码):

po = New System.Threading.Tasks.ParallelOptions()
po.MaxDegreeOfParallelism = 5
Parallel.ForEach( task_list, po, AddressOf do_work )

该程序运行正常,但我想添加一个日志文件而不是仅使用Console.WriteLine()

在do_work()Sub中,我想写入日志文件,例如:

Sub do_work( param As String )

   Dim thread_id as String = "Thread ID " & System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() & ": "

   joblog_append( thread_id & "Beg" )

   joblog_append( thread_id & "param = " & param )

   joblog_append( thread_id & "End" )

End Sub

理想情况下,我想创建三个函数,例如:

joblog_open()在程序开始时打开一个日志文件。

joblog_append()追加到日志文件;可以在任何任务中调用

joblog_close()关闭日志文件

当从在不同线程上执行的多个任务调用joblog_append()时,实现此类日志记录的正确方法是什么?

到目前为止我尝试过的所有尝试似乎都被击中了;有时数据会写入输出文件,有时则不会。

任何建议(或者更好的是代码示例)都会受到最高的赞赏。

提前致谢。

1 个答案:

答案 0 :(得分:1)

我认为您遇到的问题是由于多个线程同时访问该文件。

更好的方法是确保一次只有一个线程访问该文件。您可以使用锁(请参阅this SO)或将要写入的消息附加到string的concurrentQueue,然后在另一个线程上处理该队列。

joblog_append 调用_Logger.Log,后者依次将消息入队并启动新线程来处理队列。

private _Logger as new Logger
Private Sub joblog_append(Message As String)
 _Logger.Log(Message)
End Sub

logger类执行以下操作。

  • 将消息附加到并发队列
  • 创建并启动任务(如果尚未运行任务)将队列内容写入文件。
  • 完成后将任务设置为空

如果已经创建了任务,则该消息将被排队,并且任务本身中的While条件应该处理在其运行时添加的任何消息。

'Missing: Idisposable, Fileaccess.Shared, 
'TODO: remove debugger.break
Public class Logger
Public Property Messages As new ConcurrentQueue(Of string)
private _WorkerTask as Task 

private event WorkerTaskCompleted
private _Stream as FileStream
private _Writer as StreamWriter

Public sub New()
    _Stream = io.file.OpenWrite("Mylog.txt")
    _Writer = New StreamWriter(_Stream)
End sub


Public sub Log(Message as string)
    Messages.Enqueue(Message)
    if _WorkerTask Is Nothing
        _WorkerTask = New Task(sub()
                                   While Messages.Any
                                       Dim CurrentMessage as string = ""
                                       if Messages.TryDequeue(CurrentMessage)
                                           _Writer.WriteLine(CurrentMessage)

                                           else
                                           debugger.Break
                                       End If
                               End While
                                     _Writer.Flush
                                      _Stream.Flush
                                   RaiseEvent WorkerTaskCompleted
                               End Sub)
        _WorkerTask.Start
    End If

    End sub
    Private Sub Logger_WorkerTaskCompleted() Handles Me.WorkerTaskCompleted
    _WorkerTask = Nothing
    End Sub
    End Class

请注意。这是我解决这个问题的方法,但我没有任何类似的实现和测试。因此,您必须进行测试以确认它是否正常工作。