Giter Club home page Giter Club logo

venice's Introduction

Venice

Swift License Slack Travis Codecov Codebeat Documentation

Venice provides structured concurrency and CSP for Swift.

Features

  • Coroutines
  • Coroutine cancelation
  • Coroutine groups
  • Channels
  • Receive-only channels
  • Send-only channels
  • File descriptor polling

Venice wraps a fork of the C library libdill.

Installation

Before using Venice you need to install our libdill fork. Follow the instruction for your operating system.

macOS

On macOS install libdill using brew.

brew install zewo/tap/libdill

Linux

On Linux we have to add our apt source first. You only need to run this command once in a lifetime. You don't need to run it again if you already have.

echo "deb [trusted=yes] http://apt.zewo.io ./" | sudo tee -a /etc/apt/sources.list
sudo apt-get update

Now just install the libdill apt package.

sudo apt-get install libdill

Add Venice to Package.swift

After installing libdill just add Venice as a dependency in your Package.swift file.

import PackageDescription

let package = Package(
    dependencies: [
        .Package(url: "https://github.com/Zewo/Venice.git", majorVersion: 0, minor: 19)
    ]
)

Test Coverage

Coverage Sunburst

The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is represented by the number of statements and the coverage, respectively.

Documentation

You can check the Venice API reference for more in-depth documentation.

Structured Concurrency

Structured concurrency means that lifetimes of concurrent functions are cleanly nested. If coroutine foo launches coroutine bar, then bar must finish before foo finishes.

This is not structured concurrency:

Not Structured Concurrency

This is structured concurrency:

Structured Concurrency

The goal of structured concurrency is to guarantee encapsulation. If the main function calls foo, which in turn launches bar in a concurrent fashion, main will be guaranteed that once foo has finished, there will be no leftover functions still running in the background.

What you end up with is a tree of coroutines rooted in the main function. This tree spreads out towards the smallest worker functions, and you may think of this as a generalization of the call stack — a call tree, if you will. In it, you can walk from any particular function towards the root until you reach the main function:

Call Tree

Venice implements structured concurrency by allowing you to cancel a running coroutine.

let coroutine = try Coroutine {
    let resource = malloc(1000)
    
    defer {
        free(resource)
    }
    
    while true {
        try Coroutine.wakeUp(100.milliseconds.fromNow())
        print(".")
    }
}

try Coroutine.wakeUp(1.second.fromNow())
coroutine.cancel()

When a coroutine is being canceled all coroutine-blocking calls will start to throw VeniceError.canceledCoroutine. On one hand, this forces the function to finish quickly (there's not much you can do without coroutine-blocking functions); on the other hand, it provides an opportunity for cleanup.

In the example above, when coroutine.cancel is called the call to Coroutine.wakeUp inside the coroutine will throw VeniceError.canceledCoroutine and then the defer statement will run, thus releasing the memory allocated for resource.

Threads

You can use Venice in multi-threaded programs. However, individual threads are strictly separated. You may think of each thread as a separate process.

In particular, a coroutine created in a thread will be executed in that same thread, and it will never migrate to a different one.

In a similar manner, a handle, such as a channel or a coroutine handle, created in one thread cannot be used in a different thread.

License

This project is released under the MIT license. See LICENSE for details.

venice's People

Contributors

antonmes avatar bosr avatar czechboy0 avatar danappelxx avatar davidask avatar dreymonde avatar kandelvijayavolare avatar paulofaria avatar ratranqu avatar robertjpayne avatar tomohisa avatar yoichitgy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

venice's Issues

UDP socket support?

I noticed that your readme doesn't have UDP socket support checked off. Is this something you're planning on adding? Definitely interested in utilizing this project, but UDP is a requirement for us.

Thanks!

Compiler crash

I get a compiler crash when using Venice. Oddly enough it only happens if I use it through Xcode (launched with latest Swift toolchain). swift build works fine on both Linux and OS X.

I can investigate this further, but I want to make sure you're not aware of it and I'm not wasting time, since there is already so much yak shaving involved with Swift development.

Assertion failed: (offset >= NextOffset && "adding fields out of order"), function addField, file /Users/buildnode/jenkins/workspace/oss-swift-package-osx/swift/lib/IRGen/GenStruct.cpp, line 669.
0  swift                    0x0000000103d4ea0b llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 43
1  swift                    0x0000000103d4dcc6 llvm::sys::RunSignalHandlers() + 70
2  swift                    0x0000000103d4f0b2 SignalHandler(int) + 322
3  libsystem_platform.dylib 0x00007fff97ec1eaa _sigtramp + 26
4  swift                    0x00000001047aac15 FirstTarget + 71405
5  swift                    0x0000000103d4eec6 abort + 22
6  swift                    0x0000000103d4eea1 __assert_rtn + 81
7  swift                    0x00000001017424e0 (anonymous namespace)::ClangRecordLowering::addField(swift::VarDecl*, swift::irgen::Size, swift::irgen::LoadableTypeInfo const&) + 592
8  swift                    0x00000001017418bb swift::irgen::TypeConverter::convertStructType(swift::TypeBase*, swift::CanType, swift::StructDecl*) + 3883
9  swift                    0x0000000101750a23 swift::irgen::TypeConverter::convertAnyNominalType(swift::CanType, swift::NominalTypeDecl*) + 371
10 swift                    0x0000000101750044 swift::irgen::TypeConverter::convertType(swift::CanType) + 308
11 swift                    0x000000010174f256 swift::irgen::TypeConverter::getTypeEntry(swift::CanType) + 438
12 swift                    0x000000010174ec9e swift::irgen::IRGenModule::getTypeInfo(swift::SILType) + 46
13 swift                    0x0000000101741868 swift::irgen::TypeConverter::convertStructType(swift::TypeBase*, swift::CanType, swift::StructDecl*) + 3800
14 swift                    0x0000000101750a23 swift::irgen::TypeConverter::convertAnyNominalType(swift::CanType, swift::NominalTypeDecl*) + 371
15 swift                    0x0000000101750044 swift::irgen::TypeConverter::convertType(swift::CanType) + 308
16 swift                    0x000000010174f256 swift::irgen::TypeConverter::getTypeEntry(swift::CanType) + 438
17 swift                    0x000000010174ec10 swift::irgen::IRGenModule::getTypeInfoForLowered(swift::CanType) + 16
18 swift                    0x00000001016e1a01 swift::irgen::getTypeMetadataAccessStrategy(swift::irgen::IRGenModule&, swift::CanType, bool) + 241
19 swift                    0x00000001016e1e97 swift::irgen::IRGenFunction::emitTypeMetadataRef(swift::CanType) + 39
20 swift                    0x00000001016efff3 emitNominalMetadataRef(swift::irgen::IRGenFunction&, swift::NominalTypeDecl*, swift::CanType) + 899
21 swift                    0x00000001016ee4d9 llvm::Value* swift::CanTypeVisitor<(anonymous namespace)::EmitTypeMetadataRef, llvm::Value*>::visit<>(swift::CanType) + 345
22 swift                    0x00000001016f1129 llvm::Value* llvm::function_ref<llvm::Value* (swift::irgen::IRGenFunction&)>::callback_fn<getTypeMetadataAccessFunction(swift::irgen::IRGenModule&, swift::CanType, swift::ForDefinition_t)::$_1>(long, swift::irgen::IRGenFunction&) + 489
23 swift                    0x00000001016e1d32 swift::irgen::emitLazyCacheAccessFunction(swift::irgen::IRGenModule&, llvm::Function*, llvm::GlobalVariable*, llvm::function_ref<llvm::Value* (swift::irgen::IRGenFunction&)> const&) + 626
24 swift                    0x00000001016f0ed0 getTypeMetadataAccessFunction(swift::irgen::IRGenModule&, swift::CanType, swift::ForDefinition_t) + 192
25 swift                    0x00000001016e1f34 emitCallToTypeMetadataAccessFunction(swift::irgen::IRGenFunction&, swift::CanType, swift::ForDefinition_t) + 68
26 swift                    0x00000001016e3e5a swift::irgen::emitFieldTypeAccessor(swift::irgen::IRGenModule&, swift::NominalTypeDecl*, llvm::Function*, llvm::ArrayRef<swift::irgen::FieldTypeInfo>) + 2250
27 swift                    0x00000001016b6831 swift::irgen::IRGenModuleDispatcher::emitLazyDefinitions() + 865
28 swift                    0x0000000101759468 performIRGeneration(swift::IRGenOptions&, swift::ModuleDecl*, swift::SILModule*, llvm::StringRef, llvm::LLVMContext&, swift::SourceFile*, unsigned int) + 1368
29 swift                    0x0000000101759906 swift::performIRGeneration(swift::IRGenOptions&, swift::SourceFile&, swift::SILModule*, llvm::StringRef, llvm::LLVMContext&, unsigned int) + 70
30 swift                    0x000000010161f437 performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&) + 15447
31 swift                    0x000000010161abda frontend_main(llvm::ArrayRef<char const*>, char const*, void*) + 2794
32 swift                    0x00000001016161a7 main + 2855
33 libdyld.dylib            0x00007fff8ba8c5ad start + 1
34 libdyld.dylib            0x0000000000000060 start + 1951873716
Stack dump:
// Omitted for readability
1.  While converting type 'mill_chan' (declared at [<invalid loc> - <invalid loc>])
2.  While converting type 'mill_ep' (declared at [<invalid loc> - <invalid loc>])

Substitute global variables with Int extensions

Right now second, millisecond, minute and hour are just hardcoded Int64 values. As alternative, I propose using Int extensions to make code slightly more readable and safe:

nap(1.second)
after(5.seconds) {
    // Do something
}

It can be achieved this way:

extension Int {
    var millisecond: Int64 {
        return Int64(self * 1)
    }
    var milliseconds: Int64 {
        return millisecond
    }
    var second: Int64 {
        return Int64(self * 1000)
    }
    var seconds: Int64 {
        return second
    }
    // and so on
}

Or nicer — with protocol:

public protocol IntervalConvertible {
    var millisecond: Int64 { get }
    var second: Int64 { get }
    // and so on
}

extension IntervalConvertible {
    public var milliseconds: Int64 {
        return millisecond
    }
    public var second: Int64 {
        return millisecond * 1000
    }
    public var seconds: Int64 {
        return second
    }
    // and so on
}

extension Int: IntervalConvertible {
    public var millisecond: Int64 {
        return Int64(self * 1)
    }
}

And even now can has it’s alternative:

extension Int64 {
    public var fromNow: Int64 {
        return Clibvenice.now() + self
    }
}

So one will be able to write:

let timer1 = Timer(deadline: now + 2 * second)
let timer2 = Timer(deadline: 2.seconds.fromNow)

Better way?

Is there a better way to a achieve the following? Perhaps will only one channel? But then, I need to close it to know when all coroutines have finished. Not sure how to improve this.

import Venice

var numbers: [Int] = []

for i in 2...100 {
    numbers.append(i)
}

var primes: [Channel<Int>] = []

for number in numbers {
    let prime = Channel<Int>()
    primes.append(prime)

    co {
        for i in 2..<number {
            if number % i == 0 {
                prime.close()
                return
            }
        }

        prime <- number
        prime.close()
    }
}

for prime in primes.flatMap({ <-$0 }) {
    print("\(prime) is prime")
}

Dependency change in patch version

Hi,
Thank you for all this work.
I have been trying to build https://github.com/necolt/Swifton-TodoApp which depends on your HTTPServer and, in turn, in Venice.
I couldn't build the product because I got a dependency graph error. I have tracked the issue to this package. In version 0.7.1 it depended on C7 0.7.x while in version 0.7.2, it depends on version 0.8.
The problem is that the dependencies on Venice (HTTPServer->TCP->IP) are only targeting major and minor version, so there is no way to depend on C7 0.7.x as required by the other branch of packages. I can choose to go with 0.6.x or 0.8.x, none of which are valid for the other branch of packages.
In my opinion, based on the way that Swift Package Manager works now, you shouldn't change the dependencies on a patch version. Instead the change from C7 0.7.x to 0.8.x should happen only on Venice 0.8.0.
I think the only way to solve this is to create a new tag 0.7.3 from the 0.7.2 commit and revert the dependency on C7 to 0.7.x. The 0.8.x branch will stay as is and the issue would be resolved.
Please let me know if this isn't clear enough.

Best regards,

Jorge

Fibonacci sequence

Great work!
I just wanted to point out that the output from the Fibonacci example shows 0,1,2,4,8,16... (2^N) instead of 1,1,2,3,5,8... as one would expect.

Venice multi-threading

Can/does Venice use multiple CPU cores to execute coroutines in parallel? I can't seem to be able to get it working.

Linux Ready

What does Linux ready mean exactly?
thanks.

Cocoapods

It would be awesome if this library could be used via Cocoapods, unless there's some issue not allowing it to be.

error: extra argument in call

Looks like there's an issue with Venice 0.1.1 and compatibility with libvenice 0.1.0. I checked the brew formula and didn't see an update. Here's output from my console.

Compiling Swift Module 'Venice' (21 sources)
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Channel.swift:47:48: error: extra argument in call
        self.channel = mill_chmake(bufferSize, "Channel init")
                                               ^~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Channel.swift:51:31: error: extra argument in call
        mill_chclose(channel, "Channel deinit")
                              ^~~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Channel.swift:69:34: error: extra argument in call
            mill_chdone(channel, "Channel close")
                                 ^~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Channel.swift:77:31: error: extra argument in call
            mill_chs(channel, "Channel send")
                              ^~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Channel.swift:94:27: error: extra argument in call
        mill_chr(channel, "Channel receive")
                          ^~~~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Co.swift:45:8: error: extra argument in call
    }, "co")
       ^~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Co.swift:53:8: error: extra argument in call
    }, "co")
       ^~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Co.swift:66:21: error: missing argument for parameter #3 in call
    return goprepare(Int32(stackCount), stackSize)
                    ^
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Co.swift:71:33: error: extra argument in call
    mill_msleep(now + duration, "nap")
                                ^~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Co.swift:76:27: error: extra argument in call
    mill_msleep(deadline, "wakeUp")
                          ^~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Co.swift:81:16: error: argument passed to call that takes no arguments
    mill_yield("yield")
              ~^~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Co.swift:86:12: error: use of unresolved identifier 'mfork'
    return mfork()
           ^~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Co.swift:91:16: error: use of unresolved identifier 'mill_number_of_cores'
    return Int(mill_number_of_cores())
               ^~~~~~~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/FallibleChannel.swift:66:48: error: extra argument in call
        self.channel = mill_chmake(bufferSize, "FallibleChannel init")
                                               ^~~~~~~~~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/FallibleChannel.swift:70:31: error: extra argument in call
        mill_chclose(channel, "FallibleChannel deinit")
                              ^~~~~~~~~~~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/FallibleChannel.swift:88:34: error: extra argument in call
            mill_chdone(channel, "FallibleChannel close")
                                 ^~~~~~~~~~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/FallibleChannel.swift:96:31: error: extra argument in call
            mill_chs(channel, "FallibleChannel sendResult")
                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/FallibleChannel.swift:105:31: error: extra argument in call
            mill_chs(channel, "FallibleChannel send")
                              ^~~~~~~~~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/FallibleChannel.swift:123:31: error: extra argument in call
            mill_chs(channel, "FallibleChannel send")
                              ^~~~~~~~~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/FallibleChannel.swift:141:27: error: extra argument in call
        mill_chr(channel, "FallibleChannel receive")
                          ^~~~~~~~~~~~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/FallibleChannel.swift:157:27: error: extra argument in call
        mill_chr(channel, "FallibleChannel receiveResult")
                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Poller.swift:53:79: error: extra argument in call
    let event = mill_fdwait(fileDescriptor, Int32(events.rawValue), deadline, "pollFileDescriptor")
                                                                              ^~~~~~~~~~~~~~~~~~~~
/Users/ssoper/workspace/Runabout/Packages/Venice-0.1.1/Source/Select.swift:340:22: error: argument passed to call that takes no arguments
    mill_choose_init("select")
                    ~^~~~~~~~~
<unknown>:0: error: build had 1 command failures
swift-build: exit(1): ["/Library/Developer/Toolchains/swift-2.2-SNAPSHOT-2015-12-18-a.xctoolchain/usr/bin/swift-build-tool", "-f", "/Users/ssoper/workspace/Runabout/.build/debug/Venice.o/llbuild.yaml"]

how to cooperate with ObjC?

Use this template for simple enhancements that do not need a fully-fledged proposal.

How to cooperate with ObjC code?

Description

Is there a way to cooperate with ObjC code? For example , my project is mixed with ObjC code and Swift code, How can this 2 languages use this library and the API supports each other?

Is there any suggestion? Thanks a lot!

Please Provide More Documentation and example of Venice

thanks Venice u save my lot of time for writing code from scratch but there is not very much documentation and example of Venice

Documentation like what what class do ,what method do what about it what kind of parameter it takes what it return and a simple working example of it

it will be very helpful if you provide more documentation of Venice and Example of it

Thanks in advance
👍

Animation on each examples

GIF animations on each examples how data moving around the flowchart will makes it easier for any developers to understand. I feel there were too many examples that can gets lost.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.