Writing to a file, on multiple threads?

blov · · 492 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>So i have a program that you can select how many threads you want to run like so;</p> <pre><code> for i := 0; i &lt; n; i++ { go worker() } </code></pre> <p>And each will need to write to a single text file, But sometimes the threads try doing it at the same time making issues.</p> <p>How can i do this safely so i wont lose any data?</p> <hr/>**评论:**<br/><br/>pinpinbo: <pre><p>The easiest way is to wrap your file writing code with mutex lock.</p></pre>SaturnsVoid: <pre><p>Thanks looked into this and was able to do it.</p></pre>jerf: <pre><p>&#34;Safely&#34; here is underspecified, because that depends on a lot of things about the file.</p> <p>I have no idea what Go may guarantee here. In general I suggest that rather than parsing through code for behavior that may change anyhow that you correctly implement exactly what you want.</p> <p>The most sensible Go answer is to spawn a goroutine that is responsible for writing the file and offers a <code>chan []byte</code> that other goroutines can push to when they have something to write.</p> <p>The next most sensible answer is to decorate the file with a wrapper that implements locking, as in:</p> <pre><code> type LockedWriter struct { m sync.Mutex Writer io.Writer } func (lw *LockedWriter) Write (b []byte) (n int, err error) { lw.m.Lock() defer lw.m.Unlock() return lw.Writer.Write(b) } </code></pre> <p>However, in this case I would consider this somewhat dangerous. <code>io.Writer</code> and the other io interfaces are a bit weird, in that there is their literal Go interface specification, and then there is the sort of things that people expect those things to do that aren&#39;t written down, and are subject to opinion. I would suggest one of those opinions is that the average bit of code receiving an <code>io.Writer</code> expects that </p> <pre><code> w.Write([]byte(&#34;a&#34;)) w.Write([]byte(&#34;b&#34;)) </code></pre> <p>will result in the two writes being contiguous. This usage of the io.Writer value violates that, even with the locking in <code>LockedWriter</code>.</p> <p>(By contrast, and to give another example of the unwritten io.Writer semi-contract, an io.Writer user should <em>not</em> expect that those writes will be &#34;merged&#34;; if writing to a file that may result in two disk transactions, if writing to a socket that may result in two packets with one byte of payload each. If you want that you need an intermediate buffer yourself.)</p> <p>By making it a channel communication that is not defined by a standard interface, you have the chance to write your own semantics and your own documentation about what users can expect, whereas you really shouldn&#39;t expect to do that with io.Writer. Having something implement io.Writer but trying to &#34;document&#34; the deviations from expected behavior is a bad idea precisely because the entire point of having interfaces is passing values in to code that only knows about those interfaces and doesn&#39;t know about your prose documentation.</p></pre>ModerateBrainUsage: <pre><p>To begin with, it&#39;s not threads, it&#39;s goroutines.</p> <p>And the way I would do it, spawn another goroutine which reads from a channel and writes to a file. The worker goroutines write to the channel.</p> <pre><code>c := make(chan []byte) go func(c chan []byte) { // open file for writing, defer Close() for b := range c { // write b to file } }(c) for i := 0; i &lt; n; i++ { go worker(c) } </code></pre> <p>To make the above more correct, you might want to add a close/quit channel. Or use wait groups to keep track of your goroutines, so they don&#39;t exit too early.</p></pre>drvd: <pre><p>You can&#39;t.</p></pre>v0idl0gic: <pre><p>Bull. Besides coordinating seq. access using critical sections and you can also do this more directly if you coordinate your offsets and use WriteAt... Multiple threads of execution can call WriteAt assuming their spans do not overlap.</p> <p><a href="https://golang.org/pkg/io/#WriterAt" rel="nofollow">https://golang.org/pkg/io/#WriterAt</a></p> <blockquote> <p>Clients of WriteAt can execute parallel WriteAt calls on the same destination if the ranges do not overlap. </p> </blockquote> <p><a href="https://golang.org/pkg/os/#File.WriteAt" rel="nofollow">https://golang.org/pkg/os/#File.WriteAt</a></p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

492 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传