设计协程线程实现的替代方案,将推送方法转换为拉取方法

发布于 2024-12-06 16:50:09 字数 1549 浏览 0 评论 0原文

我有一个集合类,它以压缩格式保存许多不同类型的数据。为了枚举集合中的所有值,有一个 Execute(Query, IDataWriter) 方法。您向它传递一个定义所需数据的查询,然后对于每条匹配数据,它都会调用您传入的 IDataWriter 对象上的一个方法。IDataWriter

接口有 15 种不同的方法,每个方法对应集合中的每种不同数据类型。现在我需要将此数据提交到数据库,并且我希望能够实现 IEnumerator将数据提交到数据库。问题在于如何将调用将大量数据转储到 IDataWriter 对象(push)的 Execute 转换为 pull 方法,以便可以使用 IEnumerator 的 MoveNext 和 Current。

我研究过协程和纤程,但我发现的所有示例似乎都不适用于内部对协程一无所知的现有方法(在我的例子中为 Execute)。所以我的伪代码计划是使用线程和手动同步执行以下操作。

Execute 方法将在单独的线程中运行,我将在每个 IDataWriter 方法中手动等待并发出信号,

class EnumeratorAdapterObject : IEnumerator<SqlDataRecord>, IDataWriter
{

public EnumeratorAdapterObject(Store storeObject)
{
    workerThread = new Thread(storeObject.Execute(query, this));
}

public bool MoveNext()
{
    if (firstTimeCalled)
    {
        start worker thread
    }
    else
    {
        signal resume
    }
    block for either a call into an Add method or the Execute thread finishes

    if (not anything buffered)
        return false
    else
        return true
}


// 14 other methods like this implemented in IDataWriter, each with different types
public void Add_Decimal(IntvlDataHeader header, decimal data)
{
    buffer field of current SqlDataRecord = generate record;

    signal main thread
    wait for resume signal
}

public SqlDataRecord Current
{
    get { return buffer field of current SqlDataRecord; }
}

}

这看起来是一个好方法吗?有谁知道已经实现了这一点的任何示例或问题?

或者是否有办法利用 4.0 的新功能?我考虑过使用阻塞并发集合,其中限制为 1 个东西,但是消费者(IEnumerator 的 MoveNext)如何知道另一个线程何时完成添加内容?

I have a collection class that holds lots of different types of data in a compressed format. In order to enumerate over all of the values in the collection is has an Execute(Query, IDataWriter) method. You pass it a query that defines what data you want, and then for each piece of matching data it calls a method on the IDataWriter object you pass in.

The IDataWriter interface has 15 different methods, one for each different data type in the collection. Now I need to commit this data to the database and I want to be able to implement IEnumerator<SqlDataRecord> to commit stuff to the database. The problem comes in how to convert calling Execute which dumps a ton of data into the IDataWriter object(push), to a pull method so that the IEnumerator's MoveNext and Current can be used.

I have looked at Coroutines and fibers, but none of the examples I have found seem like they would work for an existing method (Execute in my case) that internally knows nothing of the corountine. So my plan in pseudocode is to do the following using Threads and manual synchronization.

The Execute method would be running in a seperate Thread and I would manually wait and signal it inside each IDataWriter method

class EnumeratorAdapterObject : IEnumerator<SqlDataRecord>, IDataWriter
{

public EnumeratorAdapterObject(Store storeObject)
{
    workerThread = new Thread(storeObject.Execute(query, this));
}

public bool MoveNext()
{
    if (firstTimeCalled)
    {
        start worker thread
    }
    else
    {
        signal resume
    }
    block for either a call into an Add method or the Execute thread finishes

    if (not anything buffered)
        return false
    else
        return true
}


// 14 other methods like this implemented in IDataWriter, each with different types
public void Add_Decimal(IntvlDataHeader header, decimal data)
{
    buffer field of current SqlDataRecord = generate record;

    signal main thread
    wait for resume signal
}

public SqlDataRecord Current
{
    get { return buffer field of current SqlDataRecord; }
}

}

Does this look like a good approach? Does anyone know of any examples or questions that already implement this?

Or would there be a way to take advantage of any of the new 4.0 features? I thought about using a blocking concurrent collection with a limit of 1 thing in it, but then how would the consumer(the IEnumerator's MoveNext) know when the other thread is finished adding stuff?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

感情旳空白 2024-12-13 16:50:09

我发现我可以使用阻塞集合,并在完成后调用 CompleteAdding() ,而不是使用 Signal/Wait 进行手动线程创建和同步。下面是一个简单的示例,对于我上面的问题,我将其包装在一个实现 IEnumeratorIDataWriter 的对象中,因此我将使用调用 Execute 和 Add_* 方法将调用 col.Add(new SqlDataRecord(....))

static void Main(string[] args)
{
    var col = new BlockingCollection<int>(1);

    Task.Factory.StartNew(
        () =>
        {
            GenerateStuff(col);
            col.CompleteAdding();
        });

    while (!col.IsCompleted)
    {
        Thread.Sleep(100);

        int result;
        if (!col.TryTake(out result, -1))
        {
            break;
        }
        Console.WriteLine("Got {0}", result);
    }

    Console.WriteLine("Done Adding!");
}

static void GenerateStuff(BlockingCollection<int> col)
{
    for (int i = 0; i < 10; i++)
    {
        Thread.Sleep(10);
        Console.WriteLine("Adding {0}", i);
        col.Add(i);
        Console.WriteLine("Added {0}", i);
    }
}

这还有一个优点,即运行 Execute 的工作线程将生成下一个结果与 IEnumerator 返回 Current 和 sql 代码同时执行其提交数据的操作。通过手动线程信号,一次只能运行一个线程。

Rather than doing manual Thread creation and synchronization with Signal/Wait I figured out that I can use Blocking collection with a call to CompleteAdding() when done. The following is a quick example, for my problem above I will wrap this in an object that implements IEnumerator<SqlDataRecord> and IDataWriter, so instead of the GenerateStuff call I will be calling Execute and the Add_* methods will be the ones calling col.Add(new SqlDataRecord(....))

static void Main(string[] args)
{
    var col = new BlockingCollection<int>(1);

    Task.Factory.StartNew(
        () =>
        {
            GenerateStuff(col);
            col.CompleteAdding();
        });

    while (!col.IsCompleted)
    {
        Thread.Sleep(100);

        int result;
        if (!col.TryTake(out result, -1))
        {
            break;
        }
        Console.WriteLine("Got {0}", result);
    }

    Console.WriteLine("Done Adding!");
}

static void GenerateStuff(BlockingCollection<int> col)
{
    for (int i = 0; i < 10; i++)
    {
        Thread.Sleep(10);
        Console.WriteLine("Adding {0}", i);
        col.Add(i);
        Console.WriteLine("Added {0}", i);
    }
}

This also has the advantage that the worker thread that is running the Execute will be generating the next result concurrently with the IEnumerator returning Current and the sql code doing whatever it does to commit the data. With the manual thread signalling only one thread would ever run at a time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文