# Help refactoring deprecated Task() to Channels

**URL:** https://discourse.julialang.org/t/help-refactoring-deprecated-task-to-channels/10576
**Category:** New to Julia
**Created:** [April 27, 2018, 2:32pm UTC](https://discourse.julialang.org/t/help-refactoring-deprecated-task-to-channels/10576 "2018-04-27T14:32:20Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![Joshua\_Bowles](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joshua_bowles/32/4515_2.png) [@Joshua\_Bowles](https://discourse.julialang.org/u/Joshua_Bowles)
#### Post date: [April 27, 2018, 2:32pm UTC](https://discourse.julialang.org/t/help-refactoring-deprecated-task-to-channels/10576/1 "2018-04-27T14:32:20Z")

</div>

Was reading through this blog post: [Machine Learning and Parallel Processing in Julia, Part I](http://not.patentology.com.au/2017/04/machine-learning-and-parallel.html) and saw a pattern I use a lot: walk through directories read/write files, etc…

I currently use go for that kind of work, want to see the julia way. The example from the blog post works but I’m trying to refactor it to use channels given deprecation warnings like these

```julia
WARNING: Task iteration is now deprecated. Use Channels for inter-task communication

```

However I’m having trouble getting the channel semantics correct (e.g., unable to co-ordinate between a `put!()` and `take!()` in the `readFile`, `addData`, `buildDataSet` functions posted below). Are there any blog posts or tutorials that could lead me through this particular case?

I’ve read through a similar discourse post [reading-and-processing-data-files-concurrently](https://discourse.julialang.org/t/reading-and-processing-data-files-concurrently/5972/18) but it does not address the specific pattern below.

Here is the code I’m working with:

```julia
function readFile(path::String)
    for (root, dirs, files) in walkdir(path)
        for filename in files 
            if !(filename in SKIPFILES) && filename[1] != '.'
                fullname = joinpath(root, filename)
                if isfile(fullname)
                    pastHeader, lines = false, Vector{String}()
                    open(fullname) do f 
                        for line in eachline(f)
                            if !isvalid(line)
                                line = decode(convert(Array{UInt8,1}, line), "LATIN1")
                            end
                            line = chomp(line)
                            if pastHeader
                                push!(lines, line)
                            elseif endof(line) == 0
                                pastHeader = true
                            end
                        end
                    end
                    content = join(lines, NEWLINE)
                    produce(fullname,content)
                end
            end
        end
    end
end

function addData!(df::DataFrame, path::String, classification::String)
    for (filename, text) in Task(()->readFile(path))
        push!(df, @data([text, classification, filename]))
    end
end

function buildDataSet(sources)
    df = DataFrame(text = Vector{String}(), class = Vector{String}(), index = Vector{String}())
    for (path, classification) in sources
        addData!(df, joinpath(SPAMROOT, path), classification)
    end
    return df
end

```

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [April 27, 2018, 2:41pm UTC](https://discourse.julialang.org/t/help-refactoring-deprecated-task-to-channels/10576/2 "2018-04-27T14:41:05Z")

</div>

If all you want to do is yield items lazily and consume them in a loop, then this example might help:

```julia
julia> function producer()
         Channel() do channel
           for i in 1:10
             println("producing $i")
             put!(channel, i)
           end
         end
       end
producer (generic function with 1 method)

julia> function consumer()
         for item in producer()
           @show item
         end
       end
consumer (generic function with 1 method)

julia> consumer()
producing 1
item = 1
producing 2
item = 2
producing 3
item = 3
producing 4
item = 4
producing 5
item = 5
producing 6
item = 6
producing 7
item = 7
producing 8
item = 8
producing 9
item = 9
producing 10
item = 10

```

The above uses the `Channel(::Function)` constructor, which handles all the work of creating and scheduling the producer task for you. From the `?Channel` docs:

```julia
Channel(func::Function; ctype=Any, csize=0, taskref=nothing)

  Creates a new task from func, binds it to a new channel of type ctype and size csize, and schedules the task, all in a single call.

  func must accept the bound channel as its only argument.

  If you need a reference to the created task, pass a Ref{Task} object via keyword argument taskref.

  Returns a Channel.

  julia> chnl = Channel(c->foreach(i->put!(c,i), 1:4));
  
  julia> typeof(chnl)
  Channel{Any}
  
  julia> for i in chnl
             @show i
         end;
  i = 1
  i = 2
  i = 3
  i = 4

```

---

<div class="post-metadata">

### Author: ![Joshua\_Bowles](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joshua_bowles/32/4515_2.png) [@Joshua\_Bowles](https://discourse.julialang.org/u/Joshua_Bowles)
#### Post date: [April 27, 2018, 2:47pm UTC](https://discourse.julialang.org/t/help-refactoring-deprecated-task-to-channels/10576/3 "2018-04-27T14:47:03Z")

</div>

Nice, i somehow missed the Channel docs, i saw the `c = Channel(producer)` example in Control Flow and couldn’t quite grok it… this makes a lot more sense.

Thank you. headed to meetings, will definitely try this!

---

<div class="post-metadata">

### Author: ![Joshua\_Bowles](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joshua_bowles/32/4515_2.png) [@Joshua\_Bowles](https://discourse.julialang.org/u/Joshua_Bowles)
#### Post date: [April 27, 2018, 3:21pm UTC](https://discourse.julialang.org/t/help-refactoring-deprecated-task-to-channels/10576/4 "2018-04-27T15:21:03Z")

</div>

Sure enough, simple and works.  
I’m gonna work it a bit. In go I’d typically have a goroutine per file or per batch of files. I imagine i’d have to rework it quite a bit if I wanted to run a channel on multiple cpu to large sets of files, per the discourse post here: [reading-and-processing-data-files-concurrently](https://discourse.julialang.org/t/reading-and-processing-data-files-concurrently/5972/18)

Thank you again.

I did noticed if I put the `Channel() do` block under scope of the `for (root, dirs, files) in walkdir(path)` block i get an error.

```julia
ERROR: MethodError: no method matching start(::Void)
Closest candidates are:
  start(::SimpleVector) at essentials.jl:258
  start(::Base.MethodList) at reflection.jl:560
  start(::ExponentialBackOff) at error.jl:107

```

Here is the refactored bit:

```julia
function readFile(path::String)
    Channel() do chan
        for (root, dirs, files) in walkdir(path)
            for filename in files 
                if !(filename in SKIPFILES) && filename[1] != '.'
                    fullname = joinpath(root, filename)
                    if isfile(fullname)
                        pastHeader, lines = false, Vector{String}()
                        open(fullname) do f 
                            for line in eachline(f)
                                if !isvalid(line)
                                    line = decode(convert(Array{UInt8,1}, line), "LATIN1")
                                end
                                line = chomp(line)
                                if pastHeader
                                    push!(lines, line)
                                elseif endof(line) == 0
                                    pastHeader = true
                                end
                            end
                        end
                        content = join(lines, NEWLINE)
                        put!(chan, (fullname,content))
                    end
                end
            end
        end
    end
end

function addData!(df::DataFrame, path::String, classification::String)
    for (filename, text) in readFile(path)
        push!(df, @data([text, classification, filename]))
    end
end

function buildDataSet(sources)
    df = DataFrame(text = Vector{String}(), class = Vector{String}(), index = Vector{String}())
    for (path, classification) in sources
        addData!(df, joinpath(SPAMROOT, path), classification)
    end
    return df
end

```

---

<div class="post-metadata">

### Author: ![Joshua\_Bowles](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joshua_bowles/32/4515_2.png) [@Joshua\_Bowles](https://discourse.julialang.org/u/Joshua_Bowles)
#### Post date: [April 27, 2018, 3:50pm UTC](https://discourse.julialang.org/t/help-refactoring-deprecated-task-to-channels/10576/7 "2018-04-27T15:50:07Z")

</div>

sweet, thanks for reply. When I’m done with meetings I’m gonna try adding channels too, and play with splitting out the loop at the root directory so I can get channels looping over subdirectories. Thanks again, exactly the patterns i need to get running.
